
之前在读《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>()
就会报错,因为RedApple
是Apple
的子类,不符合List<? super Apple>
的声明。这样称super
为超类型通配符也就说的通了,而且Apple
位于继承树的最底下,所以也可以称super
为下界通配符。
既然List<? super Apple>
中的元素是Apple
或Apple
的父类,那么向List<? super Apple>
中添加RedApple
也是合法的,因为RedApple
也是Apple
啊,但是添加Fruit
是不行的,因为List<? super Apple>
中存放的元素可能为Apple
。当从List<? super Apple>
中获取元素时,只能获取到Object
类型,因为假如Apple
为接口类型的话,那么元素的父类就不确定了,但所有的类都继承自Object
,Object
是确定的。所以父类型通配符一般用于向一个泛型类型中“写入”(传递给一个方法)。
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
,而Orange
和Apple
是没有关系的。所以子类型通配符一般用于从一个泛型类型中“读取”(从一个方法中返回)。
网友评论