You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将子类型集合赋值给父类型:为何两段代码报错情况不同?

嘿,这个问题刚好说到Java泛型里最容易搞混的点之一——泛型的不变性,咱们掰开揉碎了说:

为什么第一段代码能正常运行?

  • 首先,B是A的子类,这意味着new B()本身就可以向上转型为A(这是Java多态的基本特性)。
  • 你的列表l声明为List<A>,它的约束是“只能添加A或A的子类对象”,所以l.add(new B())完全符合要求,编译器自然不会报错。

为什么第二段代码会报错?

这里的核心规则是:Java中的泛型默认是不变的——哪怕B是A的子类,List<B>也绝对不是List<A>的子类。

咱们来推演一下如果允许这种赋值会发生什么恐怖的事:

  1. 假设List<A> l1 = l;是合法的,那你可以通过l1往列表里添加A的另一个子类C(比如l1.add(new C())),因为l1的泛型是A,编译器会觉得这完全合理。
  2. 但实际上这个列表的本质是List<B>,它只能容纳B类型的对象。当你之后从l(List<B>)里取元素时,会发现取出了一个C对象,这会直接导致运行时的类型转换异常——这完全违背了泛型“保证类型安全”的设计初衷。

所以Java编译器直接在编译阶段就把这种危险的赋值给禁止了,从根源上避免了潜在的bug。

如果真的需要这种“兼容父类泛型”的场景,你可以用通配符实现协变,写成:

List<? extends A> l1 = l;

不过这种情况下,你只能从l1里读取元素(读取到的是A类型),不能往里面添加任何元素(除了null),这样就严格保证了类型安全。

内容的提问来源于stack exchange,提问作者ghostrider

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:37:17