说明

? extends T

这种形式的通配符表示的是一个上界限定,表示泛型类型必须是 T 类型或其子类型。换句话说,你可以将此通配符用于读取数据,但无法向其中写入数据。

因为放入的数据都是 extends T

? super T

这种形式的通配符表示的是一个下界限定,表示泛型类型必须是 T 类型或其父类型。换句话说,你可以将此通配符用于写入数据,但无法从中读取数据。

例子1

? extends T

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.ArrayList;
import java.util.List;

public class Example {
public static void main(String[] args) {
List<? extends Number> numbers = new ArrayList<>();
// 编译器允许向上转型为 Number 类型
Number number = numbers.get(0);
// 但不允许向列表中写入数据
// numbers.add(10); // 编译错误
}
}

在这个例子中,List<? extends Number> 表示这个列表的元素类型必须是 Number 或其子类型。你可以安全地读取列表中的元素并将其向上转型为 Number 类型,但由于无法确定列表的实际类型,因此无法向其中添加任何元素。

? super T

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.ArrayList;
import java.util.List;

public class Example {
public static void main(String[] args) {
List<? super Integer> numbers = new ArrayList<>();
// 可以向列表中添加 Integer 类型的元素
numbers.add(10);
// 但不能保证从列表中读取的元素类型是 Integer,只能确定是 Object 类型
Object number = numbers.get(0);
}
}

在这个例子中,List<? super Integer> 表示这个列表的元素类型必须是 Integer 或其父类型。你可以安全地向列表中添加 Integer 类型的元素,但无法确定从列表中读取的元素的确切类型,因此只能将其转型为 Object 类型。

总的来说,? extends T? super T 是用于泛型类型限定的通配符,用于表示类型的上界和下界。使用这些通配符可以增强代码的灵活性和安全性,但需要谨慎使用,因为它们可能会使代码变得更加复杂和难以理解。

例子2

通过一个具体的示例来说明 ? extends T? super T 的用法。我们以 Fruit 类及其子类 AppleBanana 为例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码class Fruit {
public void printInfo() {
System.out.println("This is a fruit.");
}
}

class Apple extends Fruit {
@Override
public void printInfo() {
System.out.println("This is an apple.");
}
}

class Banana extends Fruit {
@Override
public void printInfo() {
System.out.println("This is a banana.");
}
}

? extends T 示例:

我们创建一个方法 printFruitInfo,它接受一个泛型类型的列表,该列表的元素类型必须是 Fruit 类型或其子类型。在这个方法中,我们只打印每个元素的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码import java.util.List;

public class Example {
public static void printFruitInfo(List<? extends Fruit> fruits) {
for (Fruit fruit : fruits) {
fruit.printInfo();
}
}

public static void main(String[] args) {
List<Apple> apples = List.of(new Apple(), new Apple());
List<Banana> bananas = List.of(new Banana(), new Banana());

printFruitInfo(apples); // 可以接受 Apple 类型的列表
printFruitInfo(bananas); // 可以接受 Banana 类型的列表
}
}

在这个例子中,printFruitInfo 方法接受一个类型为 List<? extends Fruit> 的列表。因此,它可以接受 Apple 类型的列表和 Banana 类型的列表,因为它们都是 Fruit 类型的子类型。

? super T 示例:

我们创建一个方法 addFruit,它接受一个泛型类型的列表,该列表的元素类型必须是 Fruit 类型或其父类型。在这个方法中,我们尝试向列表中添加一个新的 Fruit 对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码import java.util.List;

public class Example {
public static void addFruit(List<? super Fruit> fruits) {
fruits.add(new Fruit());
System.out.println("Added a fruit.");
}

public static void main(String[] args) {
List<Object> objects = List.of(new Object(), new Object());
List<Fruit> fruits = List.of(new Fruit(), new Fruit());
List<Apple> apples = List.of(new Apple(), new Apple());

addFruit(objects); // 可以接受 Object 类型的列表
addFruit(fruits); // 可以接受 Fruit 类型的列表
// addFruit(apples); // 编译错误,无法接受 Apple 类型的列表
}
}

在这个例子中,addFruit 方法接受一个类型为 List<? super Fruit> 的列表。因此,它可以接受 Fruit 类型的列表和 Object 类型的列表,因为它们都是 Fruit 类型的父类型。但它无法接受 Apple 类型的列表,因为 Apple 类型不是 Fruit 类型的父类型。