【问题标题】:Type casting in Java parametrized listsJava 参数化列表中的类型转换
【发布时间】:2016-09-19 21:21:55
【问题描述】:

设置

我有两个班级:

class A {

}

class B extends A {

}

还有B 类型的列表:

List<B> listOfB = new ArrayList<>();

第 1 部分:目标

我实际上想要实现的是将listOfB 的类型从B 转换为A。在Java tutorial 之后,我假设正确的方法是:

List<? extends A> listOfB = new ArrayList<>();
listOfB.add(new B()); // <--- Error here
List<A> listOfA = (List<A>) listOfB;

但是,这不允许我将 AB 类的对象添加到 listOfB。我得到的错误是:

在列表中添加(capture &lt;? extends A&gt;)不能应用于(B)

因此,我目前正在使用以下方法(效果很好):

List<A> listOfA = new ArrayList<A>(listOfB);

第 2 部分:效率

显然有一些不太好的方法 (link) 和 Java 教程中推荐的方法 (link)。

那么使用List&lt;? extends A&gt; 实现此目的的正确方法是什么?

我想知道上述方法的性能损失/收益。构造函数是否迭代认为listOfB 进行类型转换?如果是这样,随着列表变大,这是否会影响性能(与第 1 部分中的直接类型转换相比)?

【问题讨论】:

  • 你可能想阅读PECS;它可能有助于解释发生了什么以及为什么。至于您的第 2 部分,构造函数将遍历 listOfB 以将元素插入新的 ArrayList,但不涉及转换(也不需要,因为引用是已经类型 A) .构造函数只是复制引用。

标签: java list casting type-conversion


【解决方案1】:

当您编写List &lt;? extends A&gt; 时,其含义是一些扩展 A 的未知类型元素驻留在列表中,并且只有该类型的元素。您不能对元素的具体类型做出任何假设,因此您不能将 B 添加到列表中。您将无法添加任何内容,因为编译器不知道具体类型。

当你定义你的List &lt;B&gt;时,由于Lists在java中是协变的,这意味着即使B扩展了A,List &lt;B&gt;也不会扩展List &lt;A&gt;!这是有道理的:如果你能做到这一点,那就看看这个例子: 字符串扩展对象对吗? 然后你可以这样做:

List <String> a = new List <>();
a.add ("bla");
List <Object> asObj = a;
asObj.add (1);

如果你尝试迭代 a 你认为你会得到一个字符串列表,但你会得到一个 ClassCastException!

所以,问题是为什么不将您的列表定义为 List of As?

铸造不涉及构造函数迭代。编译器只是在运行前将类型擦除替换为具体类型。

【讨论】:

    【解决方案2】:

    第二种方法,ArrayList 可以只做内部数据的数组拷贝。

    B 添加到List&lt;? extends A&gt; 不起作用的原因是? 可能是B 的子类型或兄弟。所以给它加一个B是不安全的。

    class C extends A {}
    ...
    List<? extends A> listOfC = new ArrayList<C>(); // perfectly valid
    listOfC.add(new B()); // uh oh, adding B to list of C!...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多