【发布时间】:2013-06-21 20:37:50
【问题描述】:
为什么编译器只给出警告(“ArrayList 是原始类型。对泛型类型ArrayList<E> 的引用应该参数化”)并编译代码?为什么在运行时编译器无法将我们的数据类型转换为指定的参数类型而不报错?
【问题讨论】:
-
因为无论如何这些类型都会在运行时被删除。
-
结合 Oli 的注释,编译器将使用 Object 作为类型。
为什么编译器只给出警告(“ArrayList 是原始类型。对泛型类型ArrayList<E> 的引用应该参数化”)并编译代码?为什么在运行时编译器无法将我们的数据类型转换为指定的参数类型而不报错?
【问题讨论】:
对不带参数的泛型类型的引用称为raw types。
编译器允许使用它们的唯一原因是向后兼容:每一代 Java 编译器都试图尽可能向后兼容旧代码。而且由于泛型是在 Java 5 中引入的,很多旧代码根本就没有使用它们。
来自 JLS 的引述(如上链接):
仅允许使用原始类型作为对遗留代码兼容性的让步。强烈反对在将泛型引入 Java 编程语言之后编写的代码中使用原始类型。 Java 编程语言的未来版本可能会禁止使用原始类型。
由于 Sun 不想为 ArrayList 和相关类引入平行宇宙,它决定将泛型类型信息添加到集合(以及许多其他地方)并以允许旧的、非通用代码仍需编译(但有警告)。
在编写良好的新代码中,不应该与旧的和/或损坏的库原始类型接口。
【讨论】:
考虑一个未对数组列表进行参数化的示例
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”发生,所有泛型都被编译器消除。
类型擦除在this link 中进行了说明。
【讨论】: