3

我知道 Java 不允许不创建类型参数的实例。许多文章只是简单地说“Type Erase”作为原因。但是类型参数初始化不会在类型擦除之前发生吗?类型擦除是唯一的原因吗?这是一个例子:

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) 调用泛型方法时,我认为编译器会先将方法中的 E 替换为 String,然后执行“Type Erase”,对吗?如果是这样,只要我们有办法确保 E 确实有一个默认构造函数,我们应该能够创建类型参数的实例。有人可以更详细地解释为什么 Java 不允许创建参数类型的实例吗?谢谢。

4

4 回答 4

4

问:如果没有泛型,你会怎么做?

每个具有泛型的程序都可以通过简单地删除泛型参数并在适当的位置插入强制转换来转换为没有泛型的等效程序。这称为类型擦除。所以,如果你想知道你是否可以使用泛型来做到这一点,你需要首先询问你是否可以在没有泛型的情况下做到这一点。

如果没有泛型,您的程序将如下所示:

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);
    }
}
于 2013-12-27T22:24:42.373 回答
3

由于运行时类型擦除,该类型不可用于做任何事情。

但是,您可以传递类型令牌:

public static <E> void append(List<E> list, Class<E> c) {
    E elem = c.newInstance();
    list.add(elem);
}

这假定该类具有无参数构造函数。

于 2013-12-27T06:07:36.353 回答
2

请记住,泛型用于编译时检查,当您在.java文件中编译类时,Java 会为该类生成一个.class文件。

当我们使用调用泛型方法时,GenOjb.append(list);我认为编译器会先用 String 替换方法中的 E,然后执行“Type Erase”,对吗?

不,该方法中没有任何内容被替换。一旦.class文件生成,这就是你得到的。编译时,编译器只是验证该String类型是否是该方法可接受的类型参数append()。由于您没有指定任何边界E,编译器会判断这String是一个可接受的类型参数。

有人可以更详细地解释为什么 java 不允许创建参数类型的实例吗?

这不是Java语言的工作方式。类实例化发生在运行时。在运行时,由于类型擦除,不再有任何类型变量的概念,因此我们不知道是什么E

有几种选择可以获取任何类型的实例T。看这里:

于 2013-12-27T06:04:26.910 回答
0

因为在幕后, aList<E>只是一个List. 被替换的实际类型E不会在堆栈上传递。因此,JVM在运行这段代码的时候,没有办法知道是什么类型E,也就没有办法知道要实例化什么类。

于 2013-12-27T06:05:26.600 回答