Java集合协变在包装类中的运行机制及Holder赋值编译问题
问题原因与解决方案
核心原因
Java泛型类默认是不变的——哪怕类型A是类型B的子类型,Holder<A>和Holder<B>之间也不存在继承关系。而你能成功赋值List变量,是因为通配符? extends带来的协变特性,但这个特性不会自动传递给包装它的Holder类。
为什么List的赋值能通过?
List<? extends Base>是一个协变通配符类型,它表示「任意Base子类型的List」:
List<? extends Sub0>本质是「任意Sub0子类型的List」,而Sub0是Base的子类,所以它是List<? extends Base>的子类型,因此x = test0合法;List<Sub1>是「具体Sub1类型的List」,Sub1也是Base的子类,自然也属于List<? extends Base>的范畴,所以x = test1也合法。
为什么Holder的赋值失败?
你的Holder<List<? extends Base>> z是一个具体泛型类型,而Holder<List<? extends Sub0>>和Holder<List<Sub1>>是另外两个独立的具体泛型类型——它们之间没有任何继承关系,就像你不能把Holder<String>赋值给Holder<Object>一样,编译器会直接报错。
解决方法
给Holder的泛型参数也加上通配符,让它支持协变:
// 修改z的类型为带通配符的Holder Holder<? extends List<? extends Base>> z = ha; z = hb;
这样z的类型表示「任意继承自List<? extends Base>的类型的Holder」,Holder<List<? extends Sub0>>和Holder<List<Sub1>>都符合这个条件,就能正常赋值了。
内容的提问来源于stack exchange,提问作者bj0
相关产品推荐
相关产品推荐

