我知道Java不允许创建类型参数实例。许多文章只是简单地说“类型擦除”为原因。但是在类型擦除之前不会发生类型参数初始化吗?类型擦除是唯一的原因吗?这是一个例子:
public class GenObj {
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
public static main(){
List<String> list= new ArrayList<String>();
GenOjb.append<String>(list);
}
}
当我们使用GenOjb.append(list)调用泛型方法时,我认为编译器会首先用String替换方法中的E,然后执行“Type Erase”,这是正确的吗?如果是这样,只要我们有办法确保E确实有一个默认构造函数,我们就应该能够创建类型参数的实例。有人可以更详细地解释为什么Java不允许创建参数类型的实例吗?感谢。
答案 0 :(得分:4)
问:如果没有泛型,你会怎么做?
通过简单地删除通用参数并在适当的位置插入强制转换,可以将每个带有泛型的程序转换为没有泛型的等效程序。这称为类型擦除。所以,如果你想知道你是否可以使用泛型,你需要首先询问你是否可以在没有泛型的情况下做到这一点。
如果没有Generics,您的程序将如下所示:
public class GenObj {
public static void append(List list) {
Object elem = // what goes here?
list.add(elem);
}
public static main(){
List list= new ArrayList();
GenOjb.append(list);
}
}
答案 1 :(得分:3)
由于运行时类型擦除,该类型无法用于执行任何操作。
但是你可以传递一个类型标记:
public static <E> void append(List<E> list, Class<E> c) {
E elem = c.newInstance();
list.add(elem);
}
这预先假定该类具有no-args构造函数。
答案 2 :(得分:2)
请记住,Generics用于编译时检查,当您在.java
文件中编译类时,Java会为该类生成一个.class
文件。
当我们使用
GenOjb.append(list);
调用泛型方法时,我认为 编译器将先用String替换方法中的E,然后再执行 “类型擦除”,这是正确的吗?
不,该方法中没有任何内容被替换。生成.class
文件后,即可获得该文件。编译时,编译器只是验证String
类型是append()
方法的可接受类型参数。由于您在E
上未指定任何边界,因此编译器会判断String
是可接受的类型参数。
有人可以更详细地解释为什么java不允许创建 参数类型的实例?
这不是java语言的工作方式。类实例化在运行时发生。 在运行时,由于类型擦除,不再有任何类型变量的概念,因此我们无法知道E
是什么。
有一些替代方法可以获得T
类型的实例。见这里:
答案 3 :(得分:0)
因为在封面下,List<E>
只是List
。已替换E
的实际类型未在堆栈上传递。因此,当JVM运行此代码时,无法确定E
的类型,因此无法知道要实例化的类。