Spec-Zone .ru
спецификации, руководства, описания, API
След: Изучение Языка Java
Урок: (Обновленные) Обобщения
Ограничения на Обобщения
Домашняя страница > Изучение Языка Java > (Обновленные) обобщения

Ограничения на Обобщения

Чтобы использовать обобщения Java эффективно, следует рассмотреть следующие ограничения:

Не может Инстанцировать Универсальных Типов с Типами примитивов

Рассмотрите следующий параметризованный тип:

class Pair<K, V> {

    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    // ...
}

Создавая объект Pair, Вы не можете subsitute тип примитива для параметра типа K или V:

Pair<int, char> p = new Pair<>(8, 'a');  // compile-time error

Можно заменить только нетипами примитивов параметры типа K и V:

Pair<Integer, Character> p = new Pair<>(8, 'a');

Отметьте что автополя 8 to Integer.valueOf(8) и 'a' компилятора Java к Character('a'):

Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));

Для получения дополнительной информации по автоупаковке см. Автоупаковку и Распаковывание в уроке Чисел и Строк.

Не может Создать Экземпляры Параметров Типа

Невозможно создать экземпляр параметра типа. Например, следующий код вызывает ошибку времени компиляции:

public static <E> void append(List<E> list) {
    E elem = new E();  // compile-time error
    list.add(elem);
}

Как обходное решение, можно создать объект параметра типа посредством отражения:

public static <E> void append(List<E> list, Class<E> cls) throws Exception {
    E elem = cls.newInstance();   // OK
    list.add(elem);
}

Можно вызвать метод append следующим образом:

List<String> ls = new ArrayList<>();
append(ls, String.class);

Не может Объявить Статические Поля, Типы Которых являются Параметрами Типа

Статическим полем class является class уровень переменная, совместно использованная всеми нестатическими объектами class. Следовательно, статические поля параметров типа не позволяются. Рассмотрите следующий class:

public class MobileDevice<T> {
    private static T os;

    // ...
}

Если бы статические поля параметров типа были позволены, то следующий код был бы перепутан:

MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();

Поскольку статическое поле os совместно используется phone, pager, и pc, каков фактический тип os? Это не может быть Smartphone, Pager, и TabletPC одновременно. Невозможно, поэтому, создать статические поля параметров типа.

Не может Использовать Броски или instanceof с Параметризованными Типами

Поскольку компилятор Java стирает все параметры типа в универсальном коде, невозможно проверить, который параметризовал тип для универсального типа, используется во времени выполнения:

public static <E> void rtti(List<E> list) {
    if (list instanceof ArrayList<Integer>) {  // compile-time error
        // ...
    }
}

Набор параметризованных типов, которые передают к методу rtti:

S = { ArrayList<Integer>, ArrayList<String> LinkedList<Character>, ... }

Время выполнения не отслеживает параметры типа, таким образом, оно не может сказать различие между ArrayList<Integer> и ArrayList<String>. Наиболее можно сделать, должен использовать неограниченный подстановочный знак, чтобы проверить, что списком является ArrayList:

public static void rtti(List<?> list) {
    if (list instanceof ArrayList<?>) {  // OK; instanceof requires a reifiable type
        // ...
    }
}

Как правило, невозможно бросить к параметризованному типу, если он не параметризован неограниченными подстановочными знаками. Например:

List<Integer> li = new ArrayList<>();
List<Number>  ln = (List<Number>) li;  // compile-time error

Однако, в некоторых случаях компилятор знает, что параметр типа всегда допустим и позволяет бросок. Например:

List<String> l1 = ...;
ArrayList<String> l2 = (ArrayList<String>)l1;  // OK

Не может Создать Массивы Параметризованных Типов

Невозможно создать массивы параметризованных типов. Например, следующий код не компилирует:

List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error

Следующий код иллюстрирует то, что происходит, когда различные типы вставляются в массив:

Object[] strings = new String[2];
strings[0] = "hi";   // OK
strings[1] = 100;    // An ArrayStoreException is thrown.

Если бы Вы пробуете ту же самую вещь универсальным списком, была бы проблема:

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown,
                                            // but the runtime can't detect it.

Если бы массивам параметризованных списков разрешили, то предыдущий код был бы не в состоянии бросить требуемый ArrayStoreException.

Не может Создать, Поймать, или Бросить Объекты Параметризованных Типов

Универсальный class не может расширить Throwable class прямо или косвенно. Например, следующие классы не будут компилировать:

// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ }    // compile-time error

// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // compile-time error

Метод не может поймать экземпляр параметра типа:

public static <T extends Exception, J> void execute(List<J> jobs) {
    try {
        for (J job : jobs)
            // ...
    } catch (T e) {   // compile-time error
        // ...
    }
}

Можно, однако, использовать параметр типа в пункте throws:

class Parser<T extends Exception> {
    public void parse(File file) throws T {     // OK
        // ...
    }
}

Не может Перегрузить Метод Где Типы Формального параметра Каждого Стирания Перегрузки к Тому же самому Необработанному Типу

У class не может быть двух перегруженных методов, у которых будет та же самая подпись после стирания типа.

public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { }
}

Перегрузки все совместно использовали бы то же самое classfile представление и генерируют ошибку времени компиляции.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Типы Non-Reifiable
Следующая страница: Вопросы и Упражнения: Обобщения