我learned,如果我有两个班级:
public class A {}
public class B extends A {}
我可以通过这样做从List<A>
投射到List<B>
:
List<B> list = (List<B>)(List<?>) collectionOfListA;
这会产生警告,但是有效。但是,我read建议不要这样做。在那种情况下是真的吗?
如果我知道它给了我一个List<B>
,为什么要进行这种演员是一种不好的做法?
请注意,我想知道为什么,在这种情况下,这是一种不好的做法,而不是为什么会有警告。并且“这是一种不好的做法,因为它会产生警告”并不是一个好的答案。
答案 0 :(得分:13)
苹果是水果,但是苹果的列表是水果列表。
如果是的话,你可以把香蕉放在苹果列表中
答案 1 :(得分:3)
直接转换列表是不好的,因为它颠覆了Java类型系统。演员表总是会成功,但是当您去检索项目时,程序可能会在ClassCastException
之后失败,此时错误的来源可能不清楚。
通常,您希望程序尽可能靠近错误源失败。如果你强制转换列表,它可能会在某人实际尝试访问元素之前传递一段时间,并且当它抛出ClassCastException
时,可能很难将其追溯到该投射(至少硬 - 呃比演员在演员阵容中失败了。
根据您的评论,您似乎确信listA
中的所有内容实际上都是B
,在这种情况下我会建议:
List<B> listB = new ArrayList(listA.size());
for (A a : listA) {
if (a == null || a instanceof B) {
listB.add((B) a);
} else {
//Either ignore or throw exception
}
}
答案 2 :(得分:2)
为了理所当然,您必须了解List<A>
和List<B>
是两种不同的类型,而不是层次相关的,即使A
和B
是等级相关的。即使B
是A
的子类,向List<B>
投放List<A>
也是不好的,因为它可以允许您添加A
的列表实例(但不是B
)并且编译器会很乐意这样做,即使它不同意集合的实际(运行时)类型。
我不知道你可以在Java中绕过这个,但如果你能这样做只是因为类型擦除:因为Java创建了一个类,如List<Object>
,并且,对于不同的该泛型类的“实现”,它只是在编译之前在代码中添加了强制转换。这与(例如)C#形成对比,C#实际上仅将List<T>
用作“编译”模板(称为“通用定义”),以按需创建具体类型。
答案 3 :(得分:0)
泛型的工作方式不同,所以 list&lt; B&gt; 的类型不是 list&lt; A&gt; 虽然 B 是一种 A 。