我对泛型中extends和super关键字的理解

2020-04-21  本文已影响0人  ed1175f83337
《Java编程思想》泛型
之前在读《Java编程思想》中的泛型一章时,对于? super MyClass为什么叫超类型通配符一直不理解,既然可以往List<? super Apple>中添加Apple的子类,那?代表的不应该是子元素吗,如果代表的是子元素,那? extends MyClass? super MyClass有啥区别啊。今天终于从牛角尖里钻出来了,感觉自己之前好蠢,理解能力太差,哈哈哈哈...
public class GenericTest {

    public static void main(String[] args) {
        List<? super Apple> list1 = new ArrayList<Fruit>();
        List<? super Apple> list2 = new ArrayList<Apple>();        
        // 这样会报错,因为?代表的是Apple的父类
        List<? super Apple> list3 = new ArrayList<RedApple>();

        list2.add(new RedApple());
        // 这样会报错,因为list2中的元素为Apple
        list2.add(new Fruit());

        Object obj = list1.get(0);
        // 这样会报错
        Fruit fruit = list1.get(0);
        // 这样也会报错
        Apple apple = list1.get(0);
        // 这样还会报错
        RedApple redApple = list1.get(0);
    }

    private static class Fruit {}

    private static class Apple extends Fruit {}

    private static class RedApple extends Apple {}
}

其实List<? super Apple>的含义是指现有的这个容器中的元素要么是Apple,要么是Apple的父类。可以看到给List<? super Apple>赋值为ArrayList<Apple>()ArrayList<Fruit>()是没问题的,但是赋值为ArrayList<RedApple>()就会报错,因为RedAppleApple的子类,不符合List<? super Apple>的声明。这样称super超类型通配符也就说的通了,而且Apple位于继承树的最底下,所以也可以称super下界通配符
既然List<? super Apple>中的元素是AppleApple的父类,那么向List<? super Apple>中添加RedApple也是合法的,因为RedApple也是Apple啊,但是添加Fruit是不行的,因为List<? super Apple>中存放的元素可能为Apple。当从List<? super Apple>中获取元素时,只能获取到Object类型,因为假如Apple为接口类型的话,那么元素的父类就不确定了,但所有的类都继承自ObjectObject是确定的。所以父类型通配符一般用于向一个泛型类型中“写入”(传递给一个方法)。

public class GenericTest {

    public static void main(String[] args) {
        List<? extends Fruit> list1 = new ArrayList<Fruit>();
        List<? extends Fruit> list2 = new ArrayList<Apple>();
        // 这样会报错,因为?代表的是Fruit的子类
        List<? extends Fruit> list3 = new ArrayList<Plant>();
        
        // 这里0索引是没有值的哈,主要是说明下extends的特性
        Fruit fruit = list2.get(0);

        // 这样会报错
        list2.add(new Orange());
    }

    private static class Plant {}

    private static class Fruit extends Plant {}

    private static class Apple extends Fruit {}

    private static class Orange extends Fruit {}

}

super相反,List<? extends Fruit>的含义是指现有的这个容器中的元素要么是Fruit,要么是Fruit的子类,所以称extends子类型通配符,因为容器中的所有元素都继承自Fruit,所以Fruit是所有元素的上界,也就可以称extends上界通配符
既然List<? extends Fruit>中的元素都是Fruit的子类,那么从List<? extends Fruit>中获取类型为Fruit的元素自然也是合法的。但是向List<? extends Fruit>中添加元素是不允许的,可以看到虽然list2的引用类型为List<? extends Fruit>,看上去好像可以向其中添加Orange对象,但list2实际上是ArrayList<Apple>类型的列表,里面的元素都是Apple,而OrangeApple是没有关系的。所以子类型通配符一般用于从一个泛型类型中“读取”(从一个方法中返回)。

上一篇 下一篇

猜你喜欢

热点阅读