Почему вся информация о типе не стирается в Java во времени выполнения?

Мое, очевидно, неправильное понимание Дженериков Java было до сих пор, то Стирание Типа удаляет всю информацию о типе, таким образом, что нет ничего вообще во времени выполнения. Недавно я наткнулся на фрагмент кода, где я должен был спросить меня: Как взлом это работает? Упрощенный, это представляет как:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public abstract class SuperClass<T> {

    private final Type type;

    protected SuperClass(){
        ParameterizedType parameterizedType =
                (ParameterizedType) getClass().getGenericSuperclass();
        type = parameterizedType.getActualTypeArguments()[0];
    }

    public void tellMyType(){
        System.out.println("Hi, my type parameter is " + type);
    }    
}

и

public class Example {

    public static void main(String[] args) {
        SuperClass sc = new SuperClass<Integer>(){};
        sc.tellMyType();
    }
}

Выполнение Основного Класса приводит к Hi, my type parameter is class java.lang.Integer.

Что мы видим, вот, что информация о типе T также доступна во времени выполнения, которое противоречит моему начальному пониманию.

Таким образом, мой вопрос: Почему компилятор сохраняет это? Это требуется для некоторого внутреннего поведения JVM или является там каким-либо разумным объяснением этого эффекта?

25
задан Michael Myers 9 June 2011 в 17:04
поделиться

4 ответа

Из http://www.artima.com/weblogs/viewpost.jsp?thread = 208860 :

Оказывается, хотя JVM не отслеживает фактические аргументы типа для экземпляров универсального класса, она отслеживает фактические аргументы типа для подклассов универсальных классов. Другими словами, , в то время как новый ArrayList () на самом деле просто новый ArrayList () во время выполнения , если класс расширяет ArrayList , то JVM знает, что String является фактическим аргументом типа для Список параметров типа .

В вашем случае вы создаете анонимный подкласс параметризованного типа, поэтому информация о типе сохраняется. См. Статью для подробного объяснения.

18
ответ дан 28 November 2019 в 21:23
поделиться

Параметры типа удаляются только из динамических типов (т. Е. Типа создаваемого объекта):

Object o = new ArrayList<String>(); // String erased

Он сохраняется в статических типах (т. Е. Типах поля, аргумента и возвращаемого значения, throws , объявления суперкласса и суперинтерфейса):

class Test implements Superclass<String> { // String retained 
    // Accessible via Class.getGenericSuperclass()

    private List<Integer> l; // Integer retained (via Field.getGenericType())

    public void test(List<Long> l) {} // Long retained (via Method.getGenericParameterTypes())

    // Character retained (via Method.getGenericReturnType())
    public List<Character> test() { return null; }
}

В вашем случае вы создаете анонимный подкласс SuperClass , поэтому параметр типа сохраняется в объявлении суперкласса.

16
ответ дан 28 November 2019 в 21:23
поделиться

Google Guice использует это для создания TypeLiteral для представления общих классов во время выполнения. Например,

TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};

можно использовать, но

Class<List<String>> list = List<String>.class;

не компилируется.

Этот метод известен как «токен супертипа» (см. статью Нила Гафтера по этому поводу).

3
ответ дан 28 November 2019 в 21:23
поделиться
1
ответ дан 28 November 2019 в 21:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: