Имя класса параметров типа в java?

Предполагая, что T как параметр типа класса, почему я не могу использовать T.class

Я писал функцию, которая загружает страницу и анализирует ее в соответствии с пройденным классом. Для разбора я использую другую функцию, чья подпись: ParseObject::parse(Class<T> classname)

<T> void downloadParse(){
  ParseObject obj;
  obj.parse(T.class); //<--- why compiler error here?? (whereas something like Integer.class is allowed)
}

Ответ 1

Генераторы Java реализуются с помощью типа erasure. Их можно использовать только для проверки времени компиляции. После компиляции объект изменяется на самый низкий общий объект. (В этом случае Object.class).

Скомпилированный байт-код не знает, что такое T.

Если вы хотите получить доступ к классу, вам необходимо изменить способ:

<T> void downloadParse(Class<T> cls){
  ParserObject obj;
  obj.parse(cls);
}

Ответ 2

Erasure является злодеем. Из учебных пособий Java:

Например, Box преобразуется в тип Box, который называется raw type - необработанный тип - это общий класс или имя интерфейса без аргументы любого типа. Это означает, что вы не можете узнать, какой тип Объект, который использует универсальный класс во время выполнения. Следующие операции не возможны:

public class MyClass<E> {
    public static void myMethod(Object item) {
        if (item instanceof E) {  //Compiler error
            ...
        }
        E item2 = new E();       //Compiler error
        E[] iArray = new E[10];  //Compiler error
        E obj = (E)new Object(); //Unchecked cast warning
    }
}

Операции, выделенные жирным шрифтом, бессмысленны во время выполнения, поскольку компилятор удаляет всю информацию о фактическом аргументе типа (представленный параметром типа E) во время компиляции.

С помощью Erasure информация о типе удаляется, и все это просто объект:

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

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

Google "java erasure" для получения дополнительной информации о том, как это работает. Wikipedia предоставляет несколько примеров.

Ответ 3

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

Что-то, с чем вы могли бы столкнуться, это следующее:

<T> T foo(Class<T> cls) {
    Object o = ...;
    return cls.cast(o);
}

// usage - perfectly type safe
String s = foo(String.class);

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

class Foo implements Iterable<String> {
    // snip
}

ParameterizedType pt = (ParameterizedType) Foo.class.getGenericInterfaces()[0];
System.out.println(pt); // prints java.lang.Iterable<java.lang.String>

Class<?> at = (Class<?>) pt.getActualTypeArguments()[0];
System.out.println(at.getName()); // prints java.lang.String

Но эта другая история;)