【问题标题】:How to avoid downcasting when using a list of subclass items in Java在 Java 中使用子类项列表时如何避免向下转换
【发布时间】:2020-04-24 08:19:53
【问题描述】:

我有一个抽象类 A 和类 B 和 C。类 B 和 C 扩展 A。我需要将 B 和 C 放在列表中,比如 List。但是,B 和 C 有独特的方法,所以不是 List 中的所有项目都可以用来调用某些方法除非我向下转换,这被认为是一种设计味道。

我需要将 B 和 C 保留在同一个列表中,因为我想根据它们的共享属性对它们进行排序。是否将它们保留在其父类型的相同列表中,然后在这种情况下向下转换一个糟糕的设计?

【问题讨论】:

  • 既然你需要一个混合列表,你真的别无选择。
  • 是的,这是一种设计异味,但并非所有代码异味都等同于不良代码,只要您能找到好的论据来支持您对其他替代方案的决定。

标签: java generics inheritance arraylist downcast


【解决方案1】:

我需要将 B 和 C 保留在同一个列表中,因为我想根据它们的共享属性对它们进行排序。

只要要求保持列表以混合类型BC 都扩展A 并调用它们的非继承方法,你别无选择,只能使用包含所有的List<A>类型。

虽然我也尽量避免向下转换,但这并不意味着在某些情况下它既无用也无必要。

for (A item: sortedList) {
    if (item instanceof B) {
        Whatever fieldB = ((B) item).getFieldB();  // using non-inherited method of B
    } else if (item instanceof C) {
         Whatever fieldC = ((C) item).getFieldC();  // using non-inherited method of C
    } else {
         // either only A or anything different that extends A
    }
}

感谢JEP 305: Pattern Matching for instanceof,从 Java 14 开始,这样的事情变得不那么冗长了:

for (A item: sortedList) {
    if (item instanceof B b) {
        Whatever fieldB = b.getFieldB();  // using non-inherited method of B
    } else if (item instanceof C c) {
        Whatever fieldC = c.getFieldC();  // using non-inherited method of C
    } else {
        // either only A or anything different that extends A
    }
}

【讨论】:

  • 可能想要明确表示模式匹配当前是 preview feature 并且需要使用 --enable-preview 开关。
  • 对不起,什么?
猜你喜欢
  • 2018-01-18
  • 2014-07-09
  • 1970-01-01
  • 2014-08-12
  • 2021-11-06
  • 2017-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多