Java :: получение имен параметризованных типов во время выполнения

Следующий код:

public static void main(String args[]) throws NoSuchFieldException {
    List<Integer> li = new ArrayList<Integer>();
    ParameterizedType apType = (ParameterizedType) li.getClass().getGenericSuperclass();
    Type[] typeArguments = apType.getActualTypeArguments();
    int _i = 0;
    for (Type type : typeArguments) {
        System.out.format("parameterized type %d is: %s", ++_i, type);
    }
}

производит:

parameterized type 1 is: E
  1. Правильно ли я понимаю, что это связано с эффектами Type Erasure и что его следует интерпретировать как «неизвестно», учитывая, что E — это имя параметра типа?
  2. Мне кажется странным, что я каким-то образом должен интерпретировать имя «Е» (и я полагаю, что «S», «U» и т. д., если они существуют) специально. А если у меня класс "Е"? Кроме того, имя метода — get_Actual_TypeArguments. Учитывая, что параметры типа служат заполнителями так же, как и переменные, мне кажется очень странным, что метод должен возвращать имя переменной. Я что-то упустил здесь?
  3. Кроме того, мне непонятно, почему я могу привести суперкласс к ParameterizedType, но не к самому классу. Попытка привести результат li.getClass() к типу ParameterizedType приводит к следующей ошибке времени компиляции:

    требуется: ParameterizedType найден: Класс, где CAP#1 является новой переменной типа: CAP#1 расширяет список из захвата ? расширяет список

Я видел этот соответствующий пост SO, но он меня не просветил.


person Marcus Junius Brutus    schedule 02.06.2013    source источник
comment
связанные: stackoverflow.com/questions/14657542/   -  person Paul Bellora    schedule 03.06.2013


Ответы (1)


Все экземпляры универсального класса используют один и тот же класс среды выполнения:

new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()

Иными словами, среда выполнения не отслеживает фактические аргументы типа, используемые для создания экземпляра универсального класса. Однако он знает типы, объявленные в исходном коде, и это то, что возвращает функция getGenericSuperclass() и ее аналоги. Итак, если у вас есть класс:

class Environment extends HashMap<String, Object> {

}

Выражение

new Environment().getClass().getGenericSuperclass()

возвращается

java.util.HashMap<java.lang.String, java.lang.Object>

Напротив, если вы объявите

class Environment<E> extends HashMap<String, E> {
}

то же самое выражение возвращает

java.util.HashMap<java.lang.String, E>

Так что да, getGenericSuperclass возвращает фактические параметры типа, объявленные в исходном коде, но эти параметры типа могут содержать переменные типа, объявленные в другом месте.

Кроме того, мне непонятно, почему я могу привести суперкласс к ParameterizedType, но не к самому классу.

Объект ParametrizedType представляет тип времени компиляции с непустым списком аргументов типа, объект Class — тип времени выполнения (у которого нет аргументов типа). Следовательно, Class не является ParametrizedType.

person meriton    schedule 02.06.2013
comment
Что касается последнего пункта, то для меня интуитивно не очевидно, почему, имея дескриптор объекта, я могу получить аргументы типа его суперкласса, но не его класса. - person Marcus Junius Brutus; 03.06.2013
comment
Потому что объявление класса содержит тип параметры для самого класса, но тип аргументы для его суперкласса. - person meriton; 03.06.2013