?
和 T
是什么?
?
是通配符,T
是类型变量。根据字面意思,<? extends T>
表示 任何继承自类型 T
的类型,<? super T>
表示 任何是类型 T
的超类的类型。
上界和下界

泛型的关系-extends.png
下面代码就是 上界通配符(Upper Bounds Wildcards)
Plate<? extends Fruit>
它的表意是,一个能放 Fruit
及其子类的盘子。

泛型的关系-super.jpg
下面代码就是 下界通配符(Lower Bounds Wildcards)
Plate<? super Fruit>
它的表意是,一个能放 Fruit
及其父类的盘子。
PECS 原则
1. <? extends T> 不能往里存,只能往外取
class Plate<T> { private T item; public Plate(T t) { item = t; } public void set(T t) { item = t; } public T get() { return item; } }
往里存的意思就是,不能对泛型 T
类型所代表的成员变量 item
进行赋值(赋值成一种特定类型)。往外取的意思就是对泛型 T
类型所代表的成员变量 'item' 进行进行类型转换(转换成一种特定类型)。
Plate<? extends Fruit> p = new Plate<Apple>(new Apple()); // 不能被存入任何元素 p.set(new Fruit()); // exception p.set(new Apple()); // exception // 取出来的东西只能放在 Fruit 或它的基类里 Fruit fruit = p.get(); Object object = p.get(); Apple apple = p.get();
- 注意以上代码,只有在构造函数中可以对
T
类型的item
进行赋值,通过set
方法进行赋值是不行的。原因是编译器通过<? extends Fruit>
只知道Plate
接受的是Fruit
及其子类,但是具体是哪个不能确定。但是从写法上,我们在构造时已经显式地指明了Plate
的类型是Apple
,为什么编译器还不知道呢?这是因为 JVM 在设计初期就没有考虑过泛型,因此对于 JVM 编译成的字节码来说,也没有泛型的概念,JVM 会使用一个占位符 CAP#1 来表示Plate
接受一个Fruit
或子类。所以无论想往Plate
插入任何类型都不可以(因为你不能赋值一个 CAP#1 类型) - 但是,将 <? extends Fruit> 替换为一个具体的类型,
set
方法就是生效的。这是因为编译器已经知道Plate
只会接受一个确定类型的水果Apple
。
Plate<Apple> applePlate = new Plate<>(new Apple()); applePlate.set(new Apple()); Apple apple = applePlate.get(); applePlate.set(new GreenApple());
- 但是下面的写法是不被接受的。因为泛型
T
是一个类型变量,它不能被用于表达式中。
Plate<T extends Fruit> p = new Plate<>(new Apple());
- 如果写
Plate<?>
,则表示Plate
中放的是任意类型,因此什么也存不进去,可以往外取Object
Plate<?> anyPlate = new Plate<>(new Apple()); Object o = anyPlate.get();
其实存不进去的根本原因是因为,Java 类没有一个共同的子类,但是却有一个共同的父类
Object
。所以永远可以向上转型取数据,却不能向下转型存数据。
2. 下界 <? super Fruit> 不影响往里存,但是往外取只能放在 Object
使用下界 <? super Fruit>
的意思是,Plate
中存放的是任意 Fruit
的基类,但是不确定是哪一个。因此往里放 Fruit
以及其子类一定是可以的(因为这些类一定是 <? super Fruit>
的子类)。但是往外取时就只能是 Object
,因为编译器不知道你存的是 Fruit
还是 Meat
。Fruit
和 Meat
就只有一个共同父类,那就是 Object
。因此往外取 Object
一定是对的。
3. PECS(Producer Extends Consumer Super)
3.1 Producer Extends 你写的类是主要作为生产者向外提供数据,那么就用 extends
3.2 Consumer Super 你写的类是主要作为消费者,需要吃进数据,那么就用 super
作者:你可记得叫安可
链接:https://www.jianshu.com/p/0808c0029b2d
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。