为什么编译器只给出警告(“ArrayList
是原始类型。对泛型类型的引用ArrayList<E>
应该参数化”)并编译代码?为什么它不给出错误,因为在运行时编译器将无法将我们的数据类型转换为指定的参数类型?
3 回答
对不带参数的泛型类型的引用称为原始类型。
编译器允许使用它们的唯一原因是向后兼容:每一代 Java 编译器都试图尽可能向后兼容旧代码。而且自从 Java 5 中引入了泛型以来,许多旧代码根本没有使用它们。
JLS 的引述(如上链接):
仅允许使用原始类型作为对遗留代码兼容性的让步。强烈反对在将泛型引入 Java 编程语言之后编写的代码中使用原始类型。Java 编程语言的未来版本可能不允许使用原始类型。
由于 Sun 不想为ArrayList
相关类引入平行宇宙,它决定将泛型类型信息添加到集合(以及许多其他地方),并以允许旧的非泛型代码仍然编译的方式定义 JLS(但是有警告)。
在编写良好的新代码中,不应该与旧的和/或损坏的库原始类型接口。
考虑一个未参数化数组列表的示例
ArrayList listOfObjects = new ArrayList();
listOfObjects.add("someStringValue");
listOfObjects.add(new Integer(10));
listOfObjects.add(new Dog());
此处所有内容均有效,因此您可以在 listOfObjects 中添加任何内容。
但是如果你参数化它,
ArrayList<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("someStringValue");
listOfStrings.add(new Dog()); // Boom, compiler error, can't add dogs into list of strings
编译成功是因为泛型代码需要与不使用泛型的遗留代码兼容。
运行时也没有类型安全,
Java 中引入了泛型以提供集合的一致性。
即,如果您将集合传递给没有泛型的方法,那么当从集合中检索元素时,该方法将不知道会发生什么。
例如,如果您传递一个由所有没有泛型的字符串组成的集合,则该方法可能会在其中插入一个不正确的对象。
泛型仅在编译之前可用。编译后,“ type erasure
”发生,编译器消除所有泛型。
此链接中解释了类型擦除。