【问题标题】:Cast from List<A> to List<B> when B extends A当 B 扩展 A 时从 List<A> 转换为 List<B>
【发布时间】:2017-06-05 17:28:13
【问题描述】:

我有两个类:

public class A {
   //attibutes and methods
}

public class B extends A {
   //atributes and methods
}

现在我有一个服务,它返回一个 List 元素类型为 A。让我们称之为 generateAElements();

我想调用那个方法过滤得到的List保留 B 类型的元素,它们也是 A 类型。

List<A> listA = generateAElements();
List<A> listAA = listA.filter( p -> p instanceof B).collect(Collectors.toList());
List<B> listB = new ArrayList<>();
// need to create a new list, iterate overListA and add elements of type B?
for (A itemA : listA) {
    listB.add((B) itemA);       
}

有没有一种有效的方法来做到这一点?

重要提示:列表可能包含大量元素。

【问题讨论】:

标签: java list casting java-8 java-stream


【解决方案1】:

假设您使用的是 Java 8+,您可以使用流:

List<B> listB = listA
    .stream()
    .filter(B.class::isInstance)
    .map(B.class::cast)
    .collect(Collectors.toList());

当然,这在早期的 Java 版本中是可行的,只是可能更冗长。


关于术语的注释:不是“从List&lt;A&gt; 转换为List&lt;B&gt;” - 此处转换的唯一内容是个别条目。

【讨论】:

  • 从技术上讲,它正在转换,因此::cast,它只是安全转换,因为您在转换之前检查了兼容性。如果没有::isInstance,你会得到一个强制转换异常(如果有一个非 B)。
  • @Tezra - 啊,是的,我已经澄清了我的意思:)
  • 效率如何?
  • @JudgeMental - 很难想象一个人能做得比这更好(没有创建视图,这是一种作弊!)
  • O(N) 违背了问题的精神。
【解决方案2】:

流免费版本。您只需要在投射前进行兼容性检查,您就可以随心所欲。

List<A> listA = generateAElements();
List<B> listB = new LinkedList<>();
for (A item : listA) {
    // Skip non compatable items
    if(item instanceof B) 
        listB.add((B) item);       
}

与 OP 代码的主要区别在于 if(item instanceof B) 行,它执行过滤/错误检查 OP 所需的操作,但没有执行。 (这在技术上与流版本正在做的事情完全相同,但稍微冗长且开销更少)

【讨论】:

  • @PM77-1 关键区别在于if(item instanceof B) 行,它执行过滤/错误检查所需的OP,但没有执行。出于性能原因(更快的插入),我还使用 LinkList 而不是 ArrayList。
  • Tezra,您是否检查过 LinkedList 的插入速度比 ArrayList 的插入速度快?每次我测试它时,LinkedList 都会变慢,即使是 add...(顺便说一句,我没有否决你的答案)
  • @FedericoPeraltaSchaffner 如果您提前知道大小,ArrayList 会更快,因为它可以跳转到尾部索引并写入。如果超过 ArrayList 的缓冲区(OP 说他有大数据集),那么您将开始迷失于 LinkeList,因为每次超过它时 ArrayList 都必须自行销毁和重建。
  • 这仍然是 O(1) 摊销,与 LinkedList 的内存碎片相比,这可能会胜出。
  • 根据我的经验,ArrayList总是更快,无论列表的大小或您是否事先知道列表的大小。如果总是满足Z 条件,则声称XY 快是一个神话。您始终必须使用生产硬件中的真实数据对您的特定用例进行基准测试。然后,有了眼前的证据,您就可以安全地得出结论。只是我的 2 美分。
猜你喜欢
  • 2011-12-03
  • 2019-10-23
  • 2021-04-03
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
  • 2012-10-11
  • 1970-01-01
  • 2019-12-09
相关资源
最近更新 更多