开发喵星球

上下界通配符

pPeHp90.png pPeHkB4.png

本文内容是上下界通配符的梳理,本文内容包括:

需求

  1. 有水果类,有苹果类,苹果继承水果。
  2. 实现向集合里放入水果,在方法中显示集合中的水果。
  3. 实现向集合里放入苹果,在方法中显示集合中的苹果。

代码

//父类:水果
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>覆盖下图蓝色区域。

image-20230912154031385

在这个体系中,下界通配符List<? super Fruit>覆盖下图红色区域。

image-20230912154216022

小结:< ? extends T > 和 < ? super T> 的区别

   
分类:Java/OOP 作者:开发喵 发表于:2023-09-12 16:26:04 阅读量:98
<<   >>


powered by kaifamiao