这里我定义了三个类,它们之间存在以下的继承关系:
class Animal{}
class Cat extends Animal{}
class Dog extends Animal{}
问题1:泛型通配符和泛型方法在使用上下界时有什么区别吗?
public void fun(ArrayList<? extends Animal> list) { } //通配符
public <T extends Animal> void fun(ArrayList<T> list) { }//泛型方法
问题2:为什么使用这种泛型通配符和泛型方法的上下界的形式时不能添加到元素呢?
public void fun(ArrayList<? extends Animal> list) {
list.add(new Dog()); //报错:Required ?; Provide Dog
}
public <T extends Animal> void fun(ArrayList<T> list) {
list.add(new Animal());
list.add(new Cat());
list.add(new Dog());
}
问题3:为什么使用泛型方法也不可以向其中添加以及修改元素
public <T> void fun1(ArrayList<T> arrayList) {
arrayList.add(new Cat());
arrayList.add(new Animal());
}
问题4:
知乎这篇关于泛型的文章是不是错误的呢?可是在我的问题3中报错。是JDK版本问题吗?(我的是1.8)
https://zhuanlan.zhihu.com/p/...
个人观点,欢迎补充纠正。
问题1:是由区别的,如果声明在方法上,仅仅只是声明这个泛型在方法范围内的边界,其本质依然是
T
,而参数则是真正的的? extend Animal
。所以带来的结果自然也不相同,方法上是可以方法,而对List
的泛型做限定,而参数则是对泛型做限定,而无法使用方法。问题2:关于这个问题,如何使用
extend
和super
有一句口诀,当泛型是消费者的时候,使用extend
,当泛型是生产者的时候,使用super
。泛型不具备协变性,List<Object> list = new Arraylist<Integer>()
;是不能
编译的,extend
如果可能添加,直接导致泛型出现混乱,而get
确能保证安全的向上转型;具体可以参考我以前的博客:https://blog.csdn.net/perfect...问题3:这个问题和问题1重复了,明白了问题1,这个问题就解决了。
居然还有问题4:问题4 是正确的,这里的关键是
List<Object>
和List<? extend Object>
注意这两种表述是存在差异
的。前者泛型已经确定
,后者是不确定
的,确定的是可以添加的,比如add(1.2)
,而后面是不确定,意思是我也不知道会是那个class
。所以不能添加。