废话不多说,先上代码,大家可以贴在单元测试中看下以方便理解
public class ExampleUnitTest {
class Food{}
class Fruit extends Food{}
class Meat extends Food{}
class Apple extends Fruit{}
class Banana extends Fruit{}
class Pork extends Meat{}
class Beef extends Meat{}
class RedApple extends Apple{}
class GreenApple extends Apple{}
class Plate<T> {
private T item;
public Plate(T t){
this.item = t;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
@Test
public void test(){
//下面这句编译报错可以这样理解Apple is a Fruit,but Apple's Plate is not Fruit's Plate
// Plate<Fruit> plate = new Plate<Apple>(new Apple()); //Error,编译报错
//上界通配符,Plate能装所有的Fruit及Fruit的子类
Plate<? extends Fruit> plate1 = new Plate<>(new Apple());
// plate1.setItem(new Apple()); //Error 编译器不通过 无法赋值
// plate1.setItem(new Fruit()); //Error 无法赋值
//为什么即使已经指定了Apple类型却还是会报错,是因为编译器只知道容器内是Fruit或者它的子类
//上界只能从盘中取出,取出来的东西只能放在Fruit以及Fruit的基类中
Fruit item1 = plate1.getItem();//正确或有效用法
Object object = plate1.getItem();
// Apple item = plate1.getItem(); //Error 类型不匹配
//下界通配符规定了元素最小粒度的下限,既然元素是Fruit以及Fruit类型的基类,
// 那么往里存的粒度只要比Fruit类型小的都可以
Plate<? super Fruit> plate3 = new Plate<>(new Fruit());
Plate<? super Fruit> plate4 = new Plate<>(new Food());
Object item = plate3.getItem();//如果接收只能用Object类型,但取这个值毫无意义
//实际定义super下界通配符是为了set()赋值,但必须保证是Fruit以及Fruit的子类型才能编译通过
plate3.setItem(new Fruit());
plate3.setItem(new Apple());
plate3.setItem(new RedApple());
// plate3.setItem(new Food());//Error
// plate4.setItem(new Food());//Error
plate4.setItem(new Apple());
plate4.setItem(new GreenApple());
}
}
总之一句话,频繁往外读取内容用上界Extends,经常往里写入的适合用下界Super