https://www.zhihu.com/question/20400700
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
首先,泛型的出现时为了安全,所有与泛型相关的异常都应该在编译期间发现,因此为了泛型的绝对安全,java在设计时做了相关的限制:
List<? extends E>表示该list集合中存放的都是E的子类型(包括E自身),由于E的子类型可能有很多,但是我们存放元素时实际上只能存放其中的一种子类型(这是为了泛型安全,因为其会在编译期间生成桥接方法<Bridge Methods>该方法中会出现强制转换,若出现多种子类型,则会强制转换失败),例子如下:
List<? extends Number> list=new ArrayList<Number>();
list.add(4.0);//编译错误
list.add(3);//编译错误
上例中添加的元素类型不止一种,这样编译器强制转换会失败,为了安全,Java只能将其设计成不能添加元素。
虽然List<? extends E>不能添加元素,但是由于其中的元素都有一个共性--有共同的父类,因此我们在获取元素时可以将他们统一强制转换为E类型,我们称之为get原则。
对于List<? super E>其list中存放的都是E的父类型元素(包括E),我们在向其添加元素时,只能向其添加E的子类型元素(包括E类型),这样在编译期间将其强制转换为E类型时是类型安全的,因此可以添加元素,例子如下:
List<? super Number> list=new ArrayList<Number>();
list.add(2.0);
list.add(3.0);
但是,由于该集合中的元素都是E的父类型(包括E),其中的元素类型众多,在获取元素时我们无法判断是哪一种类型,故设计成不能获取元素,我们称之为put原则。
实际上,我们采用extends,super来扩展泛型的目的是为了弥补例如List<E>只能存放一种特定类型数据的不足,将其扩展为List<? extends E> 使其可以接收E的子类型中的任何一种类型元素,这样使它的使用范围更广。
List<? super E>同理。
我的一点理解:
1.List中只能存储一种类型
2.List<? extends E> 逻辑上能且只能存放E或者E的任意一个子类,姑且称为EE, 但是add没法限制 只能一种EE的子类型, Java直接不让你add, 但是get 却可以get到 这个EE类型(get到的所有子类型都是EE)
3.List<? super E> 逻辑上能且只能存放E或者E的父类型, 姑且称为SE, 所以可以 add E的任何一个子类(A) 到List中, 最后都会强制类型转换为SE, 但是get的时候, 其实只能返回SE类型, 而不能返回他的子类型, 这对开发者是有困扰的, 我放进去的是A为什么不能拿到A? Java索性不让你get