Назад Зміст Вперед

5.3. Обмеження при оголошенні Generic-класів

Обмеження на Generics

Для ефективного використання Java Generics, необхідно враховувати наступні обмеження:
  1. Неможливо створити універсальних типів з примітивними типами
  2. Неможливо створити екземпляри типу параметрів
  3. Не можна оголошувати статичні поля, типи яких Тип Параметри
  4. Неможливо використовувати зліпки або InstanceOf З параметрезованих типів
  5. Неможливо створити масиву параметрезованих типів
  6. Неможливо створити, спіймати або відкидати об'єкти параметрезованих типів
  7. Не може перевантажити спосіб, де формальні типи параметрів кожної перевантаження Erase до того ж типу Raw

1. Неможливо створити Generic типів з примітивними типами

class Pair<K, V> {

    private K key;
    private V value;

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

    // ...
}
При створенні Pair object, не можна замінити примітивний тип установка типу K або V :
Pair<int, char> p = new Pair<>(8, 'a');  // compile-time error-Помилка часу компіляції
Можна замінити тільки непримітивний типів для параметрів типу K та V :
Pair<Integer, Character> p = new Pair<>(8, 'a');
Зверніть увагу , що компілятор Java autoboxes 8 to Integer.valueOf(8) and 'a' to Character('a'):
Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));

2. Неможливо створити екземпляри типу параметрів (Type Parameters)

Не можна створити екземпляр параметра типу. Наприклад, наступний код викликає помилку компіляції:
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);

3. Не можна оголошувати статичні поля, типи яких Type Parameters

Статичні поля параметрів типу не допускаються:
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? Це не може бути SmartphonePager, і TabletPC одночасно. Не можна створювати статичні поля параметрів типу.


4. Неможливо використовувати зліпки або 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
        // ...
    }
}

5. Неможливо створити масиву параметрезованих типів

Наприклад, наступний код не компілюється:
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>[];  //Помилка компілятора, але роблять вигляд, що це дозволено
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  //ArrayStoreException повинен бути викинутий,
                                            // Але runtime не може його виявити.


Якщо масиви параметрезованих списків були дозволені, попередній код не зможе кинути потрібний ArrayStoreException .


6. Неможливо створити, спіймати або відкидати об'єкти параметрезованих типів

Загальний клас не може розширити Throwable клас прямо або побічно. Наприклад, такі класи не скомпілюються:
// 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
        // ...
    }
}

7. Не можна перевантажити Method, де формальні типи параметрів кожної Overload Erase to the Same Raw Type

Клас не може мати два перевантажених методи
public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { }
}

.