为什么Java无法创建类型参数的实例

时间:2013-12-27 05:50:42

标签: java generics generic-method

我知道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不允许创建参数类型的实例吗?感谢。

4 个答案:

答案 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的类型,因此无法知道要实例化的类。