4

有人可以向我解释为什么这段代码无法编译吗?

即使它使用泛型类而不提供特定类型 T,它也应该能够在编译时识别 ArrayList 包含字符串。

public class Test {
    public static void main(String[] args){
        Container container = new Container();
        container.strings.add("test");
        String s1 = container.strings.get(0); // does not compile
        ArrayList<String> local = container.strings;
        String s2 = local.get(0); // does compile
    }

    static class Container <T>{
        ArrayList<String> strings = new ArrayList<String>();
    }
}
4

2 回答 2

7

当您将泛型类用作原始类型(未指定类型的类型)时,所有泛型信息都会从类中剥离(无论是否使用省略的类型)。

因此,当您编写代码Container container(而不是Container<SomeClass> containerArrayList<String> stringsArrayList strings,它的使用方式就像ArrayList<Object>.

要“修复”,请指定类型Container(即使您不使用该类型):

Container<Object> container = new Container<Object>();

其余的现在将编译。


这样做的原因是为了向后兼容 Java 的早期预通用版本(1.4 和更早版本)

于 2013-01-01T23:34:04.360 回答
0

正如 Bohemian 所说,原始类型中的每个类型参数都被丢弃。一开始我认为这是一个错误,但错误数据库中甚至有一个条目(#6244346)明确引用了相关的JLS §4.8

未从其超类或超接口继承的原始类型 C 的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 8.3 节)的类型是对应的原始类型在对应于 C 的泛型声明中擦除其类型。

原始类型 C 的静态方法或静态字段的类型与其在对应于 C 的泛型声明中的类型相同。

将类型参数传递给未从其超类或超接口继承的原始类型的非静态类型成员是编译时错误。

尝试将参数化类型的类型成员用作原始类型是编译时错误。

您无法String从 raw获取 a List,但可以将 a 分配给ListaList<String>的原因是因为在后者中编译器会发出警告(未经检查的转换)但您没有报告它(您是否阅读警告,不要你呢?:P)。我使用 javac 和 Eclipse 编译器测试了您的代码,并且都遵守规范。

引入原始类型是为了与遗留代码的互操作性,但在这种情况下,我无法弄清楚如何为非静态成员保留类型信息会破坏事情。使用参数化类型而不是原始类型将意味着代码部分移植,因此在这种情况下,目的可能不仅仅是向后兼容,而是确保代码库的一致性,或者代码是完整的 1.4,或者它完全是 Java 5+。另一种选择是,使用这样的原始类型可能会减慢在类似上下文中采用无界通配符的速度。

顺便说一句(但我认为你自己想通了)如果你不使用类型参数,你可以简单地使用无界通配符,即Container<?>

于 2013-01-02T10:44:55.907 回答