0

有谁知道为什么以下禁止:

Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) collection;

而以下是允许的:

Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection;

我已经在我的一个程序中使用了第二种结构。它解决了我遇到的问题,但是连续进行两次投射对我来说看起来很奇怪。

4

4 回答 4

2

这是被禁止的,因为它会破坏泛型的目的,即确保集合实际上包含其类型状态。

几个例子。

Collection<String> strings = Arrays.asList("A", "B", "C");
// If this was allowed...
Collection<Integer> integers = (Collection<Integer>) strings;
// What would you expect from this?
for (Integer i : integers) ...

一个更微妙的情况是,用你的话来说,OtherTypeSomeType.

Collection<Integer> integers = Arrays.asList(1, 2, 3);
// Shouldn't this be legal? Integer extends Number after all?
Collection<Numbers> numbers = integers;
// I might do this then
numbers.add(2.0);
// Ouch! integers now contains a Double.
for (Integer i : integers) ...

根据情况,您可以使用extends关键字来发挥自己的优势。

Collection<Integer> integers = Arrays.asList(1, 2, 3);
// This IS legal
Collection<? extends Numbers> numbers = integers;
// This however does not compile: you cannot add anything to the Collection
numbers.add(2.0);

extends有关和super关键字的更多信息:什么是 PECS(生产者扩展消费者超级)?

于 2013-10-03T07:27:41.193 回答
1

第一个违反编译器语义,因此无法编译。但是在编译时,泛型会被删除,因此实际上您可以将任何您想要的内容存储到该集合中。

并且由于您通过第二个代码片段(通过转换为没有泛型的集合)来欺骗编译器规则,因此它将编译。

于 2013-10-03T07:15:29.200 回答
1

假设以下陈述有效:

Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) collection; //illegal

这将破坏应该提供的类型安全泛型。想象一下,您可以将 a 分配Collection<SomeType>给 a Collection<OtherType>。然后以下代码将允许您将不是 a 的内容SomeType放入 a Collection<SomeType>

otherCollection.add(new OtherType());

因为otherCollection是 a Collection<OtherType>,添加 anew OtherType()似乎完全合法。但otherCollection实际上是指类型的集合SomeType

这是允许的:

Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection;

这是 的一个含义type erasure。由于泛型几乎完全在 Java 编译器中实现,而不是在运行时中实现,所以几乎所有关于泛型类型erased的类型信息在生成字节码时就已经存在。所以在运行时,Collection<SomeType>andCollection<OtherType>是同一个类,它们都是Collection<?>. 通过这种转换,编译器将简单地发出未经检查的警告,因为它不知道强制转换是否安全。

但是,应该避免像您在第二个示例中给出的那样进行强制转换,以避免ClassCastException在运行时避免。考虑以下一系列语句:

Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection;
collection.add(new SomeType());
otherCollection.add(new OtherType());

现在在第 4 条语句之后,原始集合无法判断它包含哪些特定类型的对象;这可能会导致ClassCastException在运行时访问集合中的元素。

于 2013-10-03T07:50:55.510 回答
0

根据SCJP 6 Exam Book.-

在运行时,JVM 不知道集合的类型。所有泛型类型信息在编译过程中都会被删除,所以当它到达 JVM 时,根本无法识别将 aSomeType放入 a的灾难Collection<OtherType>

如果您尝试强制Collection<SomeType>转换为 Collection<OtherType>,编译器会阻止您,因为在运行时 JVM 将无法阻止您将 a 添加OtherType到作为SomeType集合创建的内容中。

SomeType无论如何,假设和之间存在传统关系OtherType,我猜你想做这样的事情。-

Collection<SomeType> collection = null;
Collection<? extends OtherType> otherCollection = collection;
于 2013-10-03T07:27:25.317 回答