关于java泛型中List<? extends Base>的疑问?
现在有代码如下,Sub是Base的子类:
public class Base {
}
public class Sub extends Base{
}
我能理解下面的代码:
// 相当于list2的泛型是Base或者Base的超类,
// 所以,list2中可以放Base或者Base的子类,因为list2的泛型如果是Base,那显然可以添加Base的实例;
// Base的泛型如果是其超类,那显然,Base的任意子类都能向上转型为Base的超类
List<? super Base> list1 = new ArrayList<>();
list1.add(new Sub());
list1.add(new Base());
现在的问题是,为什么不能调用list2的add方法添加,即便是添加Base实例也不行?
List<? extends Base> list2 = new ArrayList<>();
如果按照上面的理解,list2的泛型可以是Base或者Base的子类,如果说子类之间不能互相转型,那么,至少可以添加Base的实例吧?或者说,添加Base的子类也能转为Base类型,为什么java不允许这么做呢?
回复
1个回答

test
2024-07-01
因为 List<Base>
表示 里面是 Base 类型的对象但是 List<? extends Base>
表示 这是一个 List<Base>
或者 List<Sub>
因此无法判断到底能放进去什么
这里有一个比较全的例子
class Scratch {
public static void main(String[] args) {
// 类型参数是一个确定的类型的时候,读写操作都可以执行
Bag<Fruit> fruitBag = new Bag<>();
fruitBag.set(new Apple());
fruitBag.set(new Pear());
Fruit fruit = fruitBag.get();
Bag<Apple> appleBag = new Bag<>();
Bag<Pear> pearBag = new Bag<>();
// 这里会报错,因为 Bag<Fruit> 和 Bat<Apple> Bag<Pear> 类型不兼容
Bag<Fruit> badBag1 = appleBag;
Bag<Fruit> badBag2 = pearBag;
// 这里可以通过,因为 Bag<? extend Fruit> 和 Bag<Apple> 和 Bag<Pear> 类型兼容
Bag<? extends Fruit> appleFruitBag = appleBag;
Bag<? extends Fruit> pearFruitBag = pearBag;
// extends 的情况,只能'读'不能'写'
// 因为 Bag<? extend Fruit> 可能是 Bag<Apple> 也可能是<Pear>
// 所以无法确定能塞进去什么
appleFruitBag.set(new Apple());
appleFruitBag.set(new Pear());
pearFruitBag.set(new Apple());
pearFruitBag.set(new Pear());
// 但是无论是什么,都是 Fruit,所以可以读取出来
Fruit fruit1 = appleFruitBag.get();
Fruit fruit2 = pearFruitBag.get();
// super 的情况,只能'写'不能'读'(只能读出 Object)
Bag<Object> objectBag = new Bag<>();
Bag<? super Apple> superAppleBag1 = fruitBag;
Bag<? super Apple> superAppleBag2 = objectBag;
Bag<? super Apple> superAppleBag3 = appleBag;
// 因为类型范围都比 Apple 大,所以可以放 Apple 进去
superAppleBag1.set(new Apple());
superAppleBag2.set(new Apple());
// 因为不知道具体的类型是什么,因此也不能放父类对象进去
superAppleBag2.set(new Fruit());
// 同样因为不知道具体类型是什么,只能读 Object 类型出来
Object o = superAppleBag2.get();
}
public static class Bag<T> {
public void set(T t) {
}
public T get() {
return null;
}
}
public static class Fruit {
}
public static class Apple extends Fruit {
}
public static class Pear extends Fruit {
}
}
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容