看到泛型边界,这一章开始看得有点晕,所以看了下其他人的博客:
https://blog.csdn.net/jiuoop/article/details/24980991
https://blog.csdn.net/bbbbln/article/details/51943006
关于extends 和 super 写下自己的理解:
在这里首先要说:
泛型不具备协变性。
List<Object> list2 = new ArrayList<Integer>();
上面代码无法通过编译。
List<? extends Number> list1 = new ArrayList<>();
在这里 Number 被划分为上边界,这个集合想表达的意思是: 具有任何从Number继承类的类型的列表。
在这个集合中,?表示具体类型,因为只划分了上边界,所有没有最低保证,在添加的时候,无法判断这个容器到底是持有的哪个类型,只能保证它至少具有Number类型,这样在添加的时候,就有可能出现:
List<? extends Number> list1 = new ArrayList<Integer>();
list1.add(12.2);
add(? Extends Number e) 添加的时候不知道具体类型,没有办法保持数据的一致性,这里可能会有疑问,为什么不向上转型为Number? ,注意第一条协变性。
所以啊,add被禁止掉,而获取就不一样了,因为至少能够保证Number的方法,所以获取提供向上转型,这是安全的
所以add(? Extends Number e) 不接受任何类型的 Number,所以,不接受任何参数,null除外
查看相关源码:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
这里是使用的泛型参数:并没有提供向上转型的Object,而是add(E e),这里说明,那些方法是需要安全的,取决于设计者自己,通过判断泛型参数(extends),能够知道这个方法是否能被调用
List<? super Number> list1 = new ArrayList<>();
在这里,Number被划分为下边界,这个集合想表达的意思是: 具有任何从Number父类的类型的列表。
在这个集合中,?依然代表具体类型,但是由于划分出了下边界,所以就有了底线,无论如何,都能保证在这个容器中的对象不会越过这条底线,所以,就有了一种安全的做法:
List<? super Number> list1 = new ArrayList<>();
list1.add(12);
list1.add(12.2);
这是可以编译通过的:因为持有的都是Number的父类,所以,在底线下面的对象通通都是安全的:比如
List<? super Number> list1 = new ArrayList<Object>();
list1.add(12);
list1.add(12.2);