面试题答案
一键面试1.? extends T 的应用场景及解释
- 应用场景 - 集合操作:假设有一个动物类
Animal
及其子类Dog
和Cat
。当我们希望一个方法能够读取不同类型的动物集合,但不修改集合内容时,可以使用? extends T
。例如:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
public class WildcardExample {
public static void printAnimals(List<? extends Animal> animals) {
for (Animal animal : animals) {
System.out.println(animal);
}
}
}
这里List<? extends Animal>
可以接受List<Dog>
或List<Cat>
,因为Dog
和Cat
都是Animal
的子类。但该方法不能往集合中添加元素(除了null
),因为编译器无法确定具体的类型。
- 应用场景 - 方法参数传递:假设我们有一个获取集合中第一个元素的方法:
public static <T> T getFirst(List<? extends T> list) {
return list.isEmpty()? null : list.get(0);
}
这个方法可以接受任何类型的集合,只要它是T
的子类的集合,并且返回T
类型的元素。
2.? super T 的应用场景及解释
- 应用场景 - 集合操作:还是以动物类为例,当我们希望一个方法能够往集合中添加特定类型及其子类的元素时,可以使用
? super T
。例如:
public static void addDog(List<? super Dog> dogs) {
dogs.add(new Dog());
}
这里List<? super Dog>
可以接受List<Dog>
、List<Animal>
(因为Dog
是Animal
的子类)。这样就可以往集合中添加Dog
对象。
- 应用场景 - 方法参数传递:假设我们有一个将元素添加到集合的通用方法:
public static <T> void addElement(List<? super T> list, T element) {
list.add(element);
}
这个方法可以接受任何类型的集合,只要它是T
的超类的集合,并且可以将T
类型的元素添加到集合中。
3. 区别和使用原则
- 区别:
? extends T
表示类型的上界,即可以是T
或T
的子类,主要用于读取数据,因为它保证了集合中的元素类型是T
或其子类,但不能安全地添加元素(除了null
)。? super T
表示类型的下界,即可以是T
或T
的超类,主要用于写入数据,因为它保证了可以添加T
及其子类的元素到集合中,但读取元素时,得到的是Object
类型(需要类型转换,除非明确知道具体的超类类型)。
- 使用原则:
- 当你只需要从集合中读取数据时,使用
? extends T
。 - 当你只需要往集合中写入数据时,使用
? super T
。 - 当你既需要读取又需要写入数据时,不要使用通配符,而是使用具体的泛型类型。
- 当你只需要从集合中读取数据时,使用