Как общее стирание Java влияет на использование newInstance()?
Основываясь на документации Java:
Во время процесса стирания типа компилятор Java стирает все параметры типа и заменяет каждый его первой границей, если параметр типа ограничен, или Object, если параметр типа не ограничен.
Дело в том, что с таким классом:
public class MyCreator<T> {
Class<T> kind;
MyCreator(Class<T> kind) {
this.kind = kind;
}
void printInstanceClass() throws Exception{
System.out.println(kind.newInstance().getClass());
}
public static void main(String[] args) throws Exception{
MyCreator<String> myCreator = new MyCreator<String>(String.class);
myCreator.printInstanceClass();
}
}
printInstanceClass()
Метод печатает на самом деле "класс java.lang.String".
Если компилятор заменяет T внутри класса на Object, я думаю, что информация о Class также связана с kind
удаляется и заменяется классом. Итак, как можно newInstance()
метод возвращает экземпляр String вместо объекта Object?
3 ответа
Хитрая часть является String.class
параметр. Это не параметр типа, а обычный старый параметр, как String[] args
, Итак Class<T> kind
будет String.class
Таким образом printInstanceClass()
может получить к нему доступ во время выполнения.
Это обычная практика, предложенная и в Effective Java.
Таким образом, после стирания типа этот код логически эквивалентен следующему:
public class MyCreator {
Class kind; // this will be String.class at runtime
MyCreator(Class kind) {
this.kind = kind;
}
void printInstanceClass() throws Exception{
System.out.println(kind.newInstance().getClass());
}
public static void main(String[] args) throws Exception{
MyCreator myCreator = new MyCreator(String.class);
myCreator.printInstanceClass();
}
}
Вы передаете String.class (который НЕ стирается, но конкретный класс сохраняется во время выполнения), а затем вызываете newInstance для этого класса, который возвращает String.
Вывод проверяет конкретный объект (String) и отображает его класс.
Информация о классе (типе), который вы передали в качестве общего аргумента вашего myCreator
объект удален, но не информация, хранящаяся внутри kind
объект.
С помощью Class<?>
Методы объекта в порядке, но если вы пытались получить информацию о классе из универсального T
введите, что вы встретите ошибку компиляции, например:
void printInstanceClass() throws Exception{
System.out.println(T.class.newInstance().getClass()); // error!
}
Хотя это нелегко, обходные пути для выполнения вышесказанного тоже существуют.