为何List<? extends Foo>无法添加Foo类对象?技术问询
为什么List<? extends Foo>不能添加Foo对象?
嘿,这个问题其实是Java泛型里一个非常典型的通配符误区,我来给你拆解明白~
首先得搞清楚List<? extends Foo>到底代表什么:它表示这个List是属于Foo的某个子类(包括Foo自己)的列表,但我们无法确定具体是哪一个子类。举个例子,这个list有可能是ArrayList<SubFoo1>,也有可能是ArrayList<SubFoo2>,甚至就是ArrayList<Foo>——但编译器不知道它到底是哪一种。
那为什么不能add Foo对象呢?咱们想个极端情况:假设你的list实际是ArrayList<SubFoo>(SubFoo是Foo的子类),如果编译器允许你往里面加一个父类Foo的对象,那这个List里就混进了非SubFoo类型的元素,后续从List里取元素的时候,你以为取出来的都是SubFoo,实际却是Foo,这就会引发类型转换异常,完全违背了泛型的类型安全设计。所以Java编译器干脆一刀切:只要是List<? extends T>,除了null之外,任何元素都不能add进去——因为它无法保证你加的元素和List实际的类型匹配。
那你想要的“可以存放Foo子类对象的List”该怎么写?其实很简单,直接用List<Foo>就足够了!List<Foo>本身就允许存放Foo以及它所有子类的对象,完全满足你的需求。
修改你的代码如下:
final Foo[] array = new Foo[] {new Foo()}; // 把<? extends Foo>改成Foo即可 final List<Foo> list = new ArrayList<>(array.length); for (final Foo foo : array) { list.add(foo); // 现在可以正常编译啦 }
总结一下:
List<? extends T>是只读型的通配符,适合用来读取元素(比如遍历、获取元素),不适合写入;- 如果需要写入T或T的子类对象,直接用
List<T>就好; - 要是需要定义能接受任意T子类List的参数,才用
List<? extends T>,但此时同样不能往里面加元素(除了null)。
内容的提问来源于stack exchange,提问作者user7338524
相关产品推荐
相关产品推荐

