本文内容是上下界通配符的梳理,本文内容包括:
//父类:水果
class Fruit{
}
//子类:苹果
class Apple extends Fruit{
}
//测试
public class Test {
public static void showExtends(List<Fruit> fruits){//显示集合中的水果
}
public static void showSuper(List<Apple> fruits){//显示集合中的苹果
}
public static void main(String args[]){
List<Apple> apples = new ArrayList<>();
apples.add(new Apple());
showExtends(apples); // 报错
List<Fruit> fruits = new ArrayList<>();
fruits.add(new Fruit());
showSuper(fruits); // 报错
}
}
Test类第12行和第16行报编译错误。为什么?
逻辑上,水果集合当然可以放苹果,因为苹果是水果的子类,里氏替换原则是允许用子类对象代替父类对象。但实际上Java编译器不允许这个操作,
实际上,编译器的逻辑是这样的
所以,就算集合里装的东西之间有继承关系,但装苹果的集合与装水果的集合之间是没有继承关系的。
解决办法是使用上界通配符和下届通配符
把父类看作是继承关系中的上界。
上界通配符
List<? extend 父类>
表示限定了这个集合可以放的东西上界,所以上界和上界以下的东西可以放进去,即父类和子类都能放进去。
修改第3行的代码为
void showExtends(List<? extends Fruit> fruits) // 正确
把子类看作是继承关系中的下界。
下界通配符
List<? super 父类>
表示限定了这个集合可以放的东西下界,所以下界和下界以上的东西可以放进去,即子类和父类都能放进去。
修改第6行的代码为
void showSuper(List<? super Apple> fruits) //正确
如果把Fruit和Apple的例子再扩展一下,食物分成水果和肉类,水果有苹果和香蕉,肉类有羊肉和牛肉,苹果还有青苹果和红苹果。
//1级
class Food{}
//2级
class Fruit extends Food{}
class Meat extends Food{}
//3级
class Apple extends Fruit{}
class Banana extends Fruit{}
class Pork extends Meat{}
class Beef extends Meat{}
//4级
class RedApple extends Apple{}
class GreenApple extends Apple{}
在这个体系中,上界通配符List<? extends Fruit>覆盖下图蓝色区域。
在这个体系中,下界通配符List<? super Fruit>覆盖下图红色区域。
小结:< ? extends T > 和 < ? super T> 的区别
powered by kaifamiao