通用 java 擦除如何影响 newInstance() 的使用?
How is the generic java erasure affecting the usage of newInstance()?
基于 java 文档:
During the type erasure process, the Java compiler erases all type
parameters and replaces each with its first bound if the type
parameter is bounded, or Object if the type parameter is unbounded.
现在,事情是这样的 class:
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()
方法实际上正在打印 "class java.lang.String"。
如果编译器将 class 内的 T 替换为 Object,我想与 kind
关联的 Class 的信息也会被删除并替换为 Class.那么,newInstance()
方法如何 return 一个 String 实例而不是一个 Object 实例?
你传递了 String.class(它没有被擦除,但是在运行时保留了一个具体的 class),然后在那个 class 上调用 newInstance,它产生一个字符串。
输出检查具体对象 (String) 并显示其 class。
棘手的部分是 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();
}
}
有关您作为 myCreator
对象的通用参数传递的 class(类型)的信息将被删除,但存储在 kind
对象中的信息不会被删除。
使用 Class<?>
对象方法很好,但是如果您尝试从泛型 T
类型获取 class 信息,您会遇到编译错误,例如:
void printInstanceClass() throws Exception{
System.out.println(T.class.newInstance().getClass()); // error!
}
虽然这并不容易,但也存在执行上述操作的解决方法。
基于 java 文档:
During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.
现在,事情是这样的 class:
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()
方法实际上正在打印 "class java.lang.String"。
如果编译器将 class 内的 T 替换为 Object,我想与 kind
关联的 Class 的信息也会被删除并替换为 Class.那么,newInstance()
方法如何 return 一个 String 实例而不是一个 Object 实例?
你传递了 String.class(它没有被擦除,但是在运行时保留了一个具体的 class),然后在那个 class 上调用 newInstance,它产生一个字符串。
输出检查具体对象 (String) 并显示其 class。
棘手的部分是 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();
}
}
有关您作为 myCreator
对象的通用参数传递的 class(类型)的信息将被删除,但存储在 kind
对象中的信息不会被删除。
使用 Class<?>
对象方法很好,但是如果您尝试从泛型 T
类型获取 class 信息,您会遇到编译错误,例如:
void printInstanceClass() throws Exception{
System.out.println(T.class.newInstance().getClass()); // error!
}
虽然这并不容易,但也存在执行上述操作的解决方法。