为什么不能将Collection <sometype>转换为Java中的Collection <othertype>?</othertype> </sometype>

时间:2013-10-03 07:09:19

标签: java generics types

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

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

允许以下内容:

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

我已经在我的一个程序中使用了第二个构造。它解决了我遇到的问题,但连续两次演员对我来说很奇怪。

4 个答案:

答案 0 :(得分: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);

有关extendssuper个关键字的更多信息:What is PECS (Producer Extends Consumer Super)?

答案 1 :(得分:1)

第一个是反对编译器语义,所以它不会编译。但是在编译时,泛型被删除了,所以实际上你可以将你想要的任何内容存储到该集合中。

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

答案 2 :(得分:1)

假设以下陈述有效:

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

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

otherCollection.add(new OtherType());

由于otherCollectionCollection<OtherType>,因此向其添加new OtherType()似乎完全合法。但otherCollection实际上指的是SomeType类型的集合。

这是允许的:

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

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

但是应该避免使用类似于第二个示例中给出的转换,以避免在运行时ClassCastException。考虑以下一系列陈述:

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

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

答案 3 :(得分:0)

根据SCJP 6 Exam Book .-

  

在运行时,JVM不知道集合的类型。所有   在编译期间删除泛型类型信息,因此通过   它到达JVM的时间,根本无法识别   将SomeType放入Collection<OtherType>

的灾难      

如果您尝试将Collection<SomeType>投射到   Collection<OtherType>,编译器会在运行时阻止你   JVM无法阻止您添加OtherType   作为SomeType集合创建的内容。

无论如何,假设SomeTypeOtherType之间存在遗产关系,我猜你想做这样的事情.-

Collection<SomeType> collection = null;
Collection<? extends OtherType> otherCollection = collection;