【问题标题】:Java: cast collection type to subtype [duplicate]Java:将集合类型转换为子类型
【发布时间】:2009-10-30 16:50:19
【问题描述】:

假设类 B 扩展类 A。我有一个List<A>,我碰巧知道只有包含B 的实例。有没有办法可以将List<A> 转换为List<B>

似乎我唯一的选择是遍历集合,一次投射一个元素,创建一个新集合。这似乎完全浪费了资源,因为类型擦除在运行时完全没有必要。

【问题讨论】:

  • 谢谢大家的好答案。在这种情况下,强制转换为列表是最合适的解决方案。在这种情况下,我愿意为性能牺牲类型安全。

标签: java generics collections casting type-erasure


【解决方案1】:

可以通过无类型List接口进行强制转换:

List<A> a = new ArrayList<A>();
List<B> b = (List)a;

【讨论】:

  • 并在此过程中失去所有类型的安全性!如果AB 的基类,则列表可以包含A,而处理b 的代码期望它只返回B 对象。这就是为什么首先不允许这种情况的原因。
  • @Joachim,我认为这是原始问题的重点。与传统演员表相比,这种方法的唯一缺点是,如果你错了,这个 bug 直到很久以后才会出现并且更难找到,而迭代会揭示你的错误。
  • “我碰巧知道只包含 B 的实例”。只要他只使用结果列表来检索元素而不是插入它们(例如,这可能会触发对 checkedList 的运行时检查),他应该没问题。
  • 帕维尔有。问题的条件是他已经确信它只有 B 的实例。没有那个条件,这个问题甚至没有意义。
【解决方案2】:

你可以试试这个:

List<A> a = new ArrayList<A>();
List<B> b = (List<B>) (List<?>) a;

它基于 jarnbjo 的回答,但基于不使用原始列表。

【讨论】:

    【解决方案3】:

    List&lt;A&gt;不是List&lt;B&gt;的子类型!

    The JLS even mentions that explicitly:

    子类型不通过泛型类型扩展:T &lt;: U 并不暗示 C&lt;T&gt; &lt;: C&lt;U&gt;

    【讨论】:

    • 恕我直言:这取决于。由于类型擦除,在运行时List&lt;A&gt; 变为ListList&lt;B&gt; 变为List,因此您的语句在运行时为假,因为List 子类型(如List可分配)。
    • @pkk:仅当您仅从 JVM 角度查看类型系统时才适用。泛型几乎完全是一种语言级别的构造,因此 JVM 对此知之甚少(我同意你的观点)。 但是泛型的全部意义在于它们可以与遗留代码结合使用,并且iff编译器不会发出警告,它们的保证将成立。通过原始类型进行强制转换(即做 JVM 无论如何都会做的事情)破坏了类型系统,从而破坏了泛型的目的。
    • 没错。但是,我仍然想知道,为什么在语法级别上,以下含义不成立(即 not 在语言级别上实现,而 IMO 应该 实现):@ 987654332@ 这将解决上述问题(可能还有其他与 Java 中使用泛型有关的问题。
    • @pkk:Foo&lt;A&gt; 可能意味着两件事:它接受所有A 它只返回A(或两者,甚至可能在相同的方法中)。对于“它接受所有A”(例如,作为方法参数),您的建议将成立。但是对于“它只返回 A”,它不会:Foo&lt;A&gt;不会返回 B(当然可以,但不能保证)。
    【解决方案4】:

    一种在对性能影响最小的情况下保留某种类型安全性的方法是使用wrapper。这个例子是关于 Collection 的,List 的情况会非常相似,也许有一天我也会写。如果有人在我之前,请让我们分享代码。

    【讨论】:

      猜你喜欢
      • 2018-10-26
      • 1970-01-01
      • 2021-01-11
      • 1970-01-01
      • 2021-09-03
      • 2010-10-07
      • 2012-04-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多