有谁知道为什么禁止以下内容:
Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) collection;
允许以下内容:
Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection;
我已经在我的一个程序中使用了第二个构造。它解决了我遇到的问题,但连续两次演员对我来说很奇怪。
答案 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) ...
更微妙的情况是,在您的条件中,OtherType
是SomeType
的超类型。
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
个关键字的更多信息: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());
由于otherCollection
是Collection<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
集合创建的内容。
无论如何,假设SomeType
和OtherType
之间存在遗产关系,我猜你想做这样的事情.-
Collection<SomeType> collection = null;
Collection<? extends OtherType> otherCollection = collection;