Ограничение переменных типов Java

Ограничение переменных типов JavaИногда класс или метод нуждается в наложении ограничений на переменные типов. Приведем типичный пример. Нужно вычислить минимальный элемент массива:

class ArrayAlg
{
public static <T> T min(T[] a)  //  
{
if(a == null || a.length == 0) return null;
T smallest = a[0];
for(int i = 1; i < a.length; i++)
if(smallest.compareTo(a[i]) > 0) smallest = a[i];
return smallest;
}
}

Но здесь есть проблема. Взгляните на код метода min(). Переменная smallest имеет тип Т, а это означает, что она может быть объектом произвольного класса. Откуда мы знаем, имеет ли класс Т метод compareTo()?Решение заключается в том, чтобы наложить ограничение на тип Т, чтобы вместо него можно было подставлять только класс, реализующий Comparable - стандартный интерфейс с единственным методом compareTo(). Это делается добавлением ограничения (bound) переменной типа Т:

public static <T extends Comparable> T min(T[] a) . . .

В действительности интерфейс Comparable сам является обобщенным типом. Пока мы проигнорируем эту сложность и предупреждения, которые генерирует компилятор.

Теперь обобщенный метод min() может вызываться только с массивами классов, реализующих интерфейс Comparable, таких как String, Date и тому подобнее. Вызов min() с массивом Rectangle даст ошибку во время компиляции, поскольку класс Rectangle не реализует Comparable.

В C++ вы не можете ограничить типы в параметрах шаблонов. Если программист создаст экземпляр шаблона с неправильным типом, сообщение об ошибке(часто невнятное) появится в шаблонном коде.

Вас может удивить, почему здесь используется ключевое слово extends вместо implements, весь Comparable - это интерфейс? Обозначение:

<T extends _>

говорит о том, что Т должен быть подтипом ограничивающего типа. Ключевое слово extends выбрано потому, что это резонное приближение концепции подтипа, и проектировщики Java не хотели добавлять в язык новое ключевое слово(такое как sub).

Переменная типа или тип подстановки могут иметь несколько ограничений. Например:

T extends Comparable & Serializable

Ограничивающие типы разделяются знаком &, потому что запятые используются для разделения переменных типа.

Как и в наследовании Java, вы можете иметь столько интерфейсных подтипов, сколько хотите, но только один из ограничивающих типов может быть классом. Если вы используете для ограничения класс, он должен быть первым в списке ограничений.

В программе которая будет представлена ниже, метод вычисляет минимум и максимум в обобщенным массиве, возвращая Pair<T>.

import java.util.*;

public class PairTest2
{
    public static void main(String[] args)
    {
        GregorianCalendar[] birthdays = 
            {
                new GregorianCalendar(1906, Calendar.DECEMBER, 9),  // G.Hoper
                new GregorianCalendar(1815, Calendar.DECEMBER, 10), // A. Lovelace
                new GregorianCalendar(1903, Calendar.DECEMBER, 3),  // J. von Neumann
                new GregorianCalendar(1910, Calendar.DECEMBER, 22), // K.Zuse
            };
        Pair<GregorianCalendar> mn = ArrayAlg.minmax(birthdays);
        System.out.println("min = " + mm.getFirst().getTime());
        System.out.println("max = " + mm.getSecond().getTime());
    }
}
class ArrayAlg
{
    /**
     *         .
     * @param     
     * @return      
     *  null,      null
     */
    public static <T extends Comparable> Pair<T> minmax(T[] a)
    {
        if(a == null || a.length == 0) return null;
        T min = a[0];
        T max = a[0];
        for(int i = 1; i < a.length; i++)
        {
            if(min.compareTo(a[i]) > 0) min = a[i];
            if(max.compareTo(a[i]) < 0) max = a[i];
        }
        return new Pair<T>(min, max);
    }
}

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *