问题一:
List<? extends Number> list = new ArrayList<>();
list .add(100); //这样的代码会报错的
为啥这样的List就不能调用add函数呢? 奇怪,明明100是Integer对象类型,然后Integer是Number的子类,符合<? extends Number>上线限制的原则啊,,,为啥就报错了呢?
这样的问题,网上很多回答的,但总是说类型不安全,导致不让add。。。。说的一塌糊涂,,,让我想了好久,最后我根据我的理解,整理出来,方便大家理解,有哪里说的不对的,欢迎指正。
2. 还有种解释是,,,现在JAVA的强类型检测,当编辑器遇到<? extends Number>时候,他只知道有东西要加入了,至于具体是什么类型,就不得而知了,所以在声明该变量的时候,只是存了一个变量加入类型的标记符,也就是占位符,具体是什么类型,还不能确定。。。当list调用add函数加入的时候, 会进行类型判断的,这个时候,因为上面保存的只是占位符,却没有真正的标记变量的类型。。。导致没法判断,就这样JAVAl数据类型的强类型问题问题,就会导致报错和各种问题,所以JAVA就直接不让add了,从而避免了该问题的发生。
问题二:
List<? super Number> listb = new ArrayList<>();
Integer a = 10;
listb.add(a);
listb.add((Object)a) //这个的add会报错的
为啥这里的listb.add(a)不会报错,而listb.add(Object)对象会报错呢?
首先先说,为啥add Integer对象成功了。。。其实是这样的,因为JAVA的继承原理,对应的属性图都是从上到下的方式,Integer对象肯定是Number对象。。。而List<? super Number> list可以存储的就是Number类或者Number类的父类,但具体是哪个类型,就不得而知了。。。当然编译器也是不知道的。。。但就是因为JAVA的继承原理,让每一个Number子类都同时是Number类,,,同时也是所以Number父类的子类。。。这不就是完全符合了List<? super Number>list 可以存储的要求了吗? 因为Number子类,全部可以看成是Number类,然后Number类都是可以符合该List要求的。。。。那这样明显就可以存储成功了啊。。。
然后在说add Object失败的问题,很明显,在申明一次,List<? super Number> list存储的只能是Number类或者Number类的父类,但具体是哪个类??? 谁知道啊,,,有谁知道吗??? 鬼都不知道,编辑器当然也是不知道的
。。。这个时候,你add object对象,编辑器都不知道里面存储的数据类型,因为JAVA的强类型和Java类型检测机制,,,这里就会报错啦。。。。
问题3:
基于上面的考虑,List<? extends Number>list 都不能add,,,那有这个东西有什么用呢? 这个自己体会吧,,,简单说明一下,抽象类和接口都不能new对象,怎么就那么大作用呢? 道理是一样的,,,比如如下:
List<? super Number> list = new Arrary<>();
List<Integer> listb = new Arrary<>();
list = listb;
这就是用到的地方,对类型进行限制。。。其他的自己体会下吧,,,
总结:
当考虑到要add时候,对于安全性的考虑,应该使用泛型的<? super XXX>模式,当考虑到要对list进行get类型显示的时候,就要考虑用到<? extends XXX>,这样的泛型才能起到,类型安全,并且简洁,程序员开发直观的效果!!!!!!