为什么要从列表<a> to List<b> not recommended?</b></a>进行投射

时间:2013-01-15 12:12:05

标签: java list casting

learned,如果我有两个班级:

public class A {}
public class B extends A {}

我可以通过这样做从List<A>投射到List<B>

List<B> list = (List<B>)(List<?>) collectionOfListA;

这会产生警告,但是有效。但是,我read建议不要这样做。在那种情况下是真的吗?

如果我知道它给了我一个List<B>,为什么要进行这种演员是一种不好的做法?

请注意,我想知道为什么,在这种情况下,这是一种不好的做法,而不是为什么会有警告。并且“这是一种不好的做法,因为它会产生警告”并不是一个好的答案。

4 个答案:

答案 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>是两种不同的类型,而不是层次相关的,即使AB是等级相关的。即使BA的子类,向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