在 Java 泛型中,extends
和 super
用于限定泛型的上界和下界,它们的核心区别在于:
? extends T
限定 上界(Upper Bound),表示该类型是T
或T
的子类。? super T
限定 下界(Lower Bound),表示该类型是T
或T
的父类。
extends
和 super
的详细区别
1. ? extends T
—— 上界通配符
- 语法:
? extends T
- 含义:泛型类型必须是
T
本身或者T
的子类。 - 应用场景:用于只读数据,不能安全地向集合中添加元素(除了
null
)。 - 适用原则:"Producer extends"(生产者使用
extends
)——如果你只需要从泛型对象中读取数据,而不修改它(不向其中添加新元素),使用extends
。
示例
class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }
public class Test {
public static void printAnimals(List<? extends Animal> list) {
for (Animal a : list) {
System.out.println(a);
}
// list.add(new Animal()); // ❌ 编译错误
// list.add(new Dog()); // ❌ 编译错误
}
public static void main(String[] args) {
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
List<Cat> cats = new ArrayList<>();
cats.add(new Cat());
printAnimals(dogs); // ✅ 可以传递 List<Dog>
printAnimals(cats); // ✅ 可以传递 List<Cat>
}
}
解释:
List<? extends Animal>
允许传入List<Dog>
或List<Cat>
。- 但不能向
list
添加任何元素(除了null
),因为 Java 编译器无法确定list
具体是哪种Animal
的子类,可能是List<Dog>
,也可能是List<Cat>
。
2. ? super T
—— 下界通配符
- 语法:
? super T
- 含义:泛型类型必须是
T
本身或者T
的父类。 - 应用场景:用于写入数据,通常用来添加元素,但读取元素时类型只能保证是
Object
。 - 适用原则:"Consumer super"(消费者使用
super
)——如果你只需要向泛型对象中写入数据,而不关心读取的数据具体类型,使用super
。
示例
class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }
public class Test {
public static void addDogs(List<? super Dog> list) {
list.add(new Dog()); // ✅ 可以添加 Dog
// list.add(new Animal()); // ❌ 编译错误
// list.add(new Object()); // ❌ 编译错误
}
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
List<Object> objects = new ArrayList<>();
addDogs(animals); // ✅ 可以传 List<Animal>
addDogs(objects); // ✅ 可以传 List<Object>
}
}
解释:
List<? super Dog>
允许传入List<Animal>
或List<Object>
,因为Animal
和Object
都是Dog
的父类。- 但只能安全地向
list
添加Dog
或Dog
的子类。 - 读取数据时,返回类型只能是
Object
,因为list
可能是List<Object>
,编译器无法确定存储的具体类型。
extends
和 super
的核心区别总结
对比项 | ? extends T | ? super T |
---|---|---|
适用方向 | 上界通配符(Upper Bound) | 下界通配符(Lower Bound) |
可传入的类型 | T 或 T 的子类 (T itself, T 's subclasses) | T 或 T 的父类 (T itself, T 's superclasses) |
适合场景 | 只读(生产者 Producer) | 只写(消费者 Consumer) |
能否添加元素 | 不能(除了 null ) | 可以添加 T 或 T 的子类 |
能否读取元素 | 读取时,类型安全(返回 T 或 T 的父类) | 读取时,只能保证是 Object |
如何选择 ? extends
和 ? super
?
- 如果你需要读取数据,但不写入:用
? extends T
。 - 如果你需要写入数据,但不读取:用
? super T
。 - 如果即要读取又要写入,就不能用通配符,应直接使用
T
。
经典口诀
- "Producer extends, consumer super"(生产者使用
extends
,消费者使用super
)。 - "上界安全读取(extends 适合读),下界安全写入(super 适合写)"。