java泛型的几点总结
1 父类是个泛型类,子类继承父类,如果不指定父类的泛型类型或者没有重新声明一个泛型,那么子类讲不是一个泛型类
public class Parent<T> { } public class Son extends Parent { }
下面这样写是会报错的
Son<Integer> song = new Son<Integer>();
2 类型通配符
2.1 <? extends xx>
Number obj = new Integer(123); List<Integer> integerList = new ArrayList<>(); List<Number> numberList = integerList;
java对象,父类型可以引用所有的子类实现,如上第一行代码Number引用类型可以引用Integer对象
而List<Number>和List<Integer>没有任何上下级关系,List<Number>是不能引用List<Integer>的,上面的最后一行代码会报错,而数组确可以,因为数组是协变的,如下代码是合法的
Integer[] integerArry = new Integer[1]; Number[] numberArry = integerArry;
类似Number引用Integer,如果我想用List<Number>引用List<Integer>怎么办?
List<? extends Number>就是用来解决这个问题的,除了Integer,任何继承自Number的类都可以引用。
通过类型通配符List<? extends Number>引用会产生副作用:
(1)可以get列表中的值,并且用Object或Number来引用这个值。
Object好理解,它可以引用任何类型
由于List<? extends Number>所引用的列表中的元素类型一定是Number的子类型,所有可以用Number引用也好理解
(2)不能set除了null以外的任何值
因为List<? extends Number>可以引用任何Number子类型的List,具体是哪一个,无法得知,也是就是不知道List中的原始是什么类型(只知道是Number的子类型),所以也就无法set元素。
说了半天,List<? extends Number>究竟是用来解决什么问题的?难道仅仅是引用更多类型参数的List吗?或者说,引用更多类型参数的List可以达到什么目的?假设有这样一个场景,提供一个方法,方法的入参是List<Number>,这个方法的逻辑就是把这个列表中的值取出来,执行某些操作。取出元素后,通过Number来引用元素,然后执行某些操作,代码完全是针对Number类型来写的。理论上针对Number类型写的代码,同样适用于Number的所有子类(面向接口编程),所以泛型类型是Number子类的List,也可以在这个方法中得到正确的处理。但是我们怎么才能支持,所有泛型类型是Number子类的list可以传递到这个方法中,List<Number>肯定不支持,List<? extends Number>正好可以满足这个需求。请注意,仅仅是把列表中的元素取出来,如果要往这个列表中set元素,这是List<? super Number>所要解决的问题。List<? super Number>可以引用任何泛型类型是Number或这Number父类的List
List<? super Number>副作用:
(1)可以取出原始,但是只能被Object引用。父类型不确定是哪一个,所有只能用最顶层类型Object引用
(2)只能设置null或者Number的任何子类型,包含Number。java中父类型可以引用任何子类型,<? super Number>可以确定的是,元素类型一定是Number的父类型,所以Number或者它的子类型,一定可以被引用,所以理所当然的就可以被设置进去。
用来解决什么问题,加上有个方法的入参是List<Number>,这个方法的逻辑就是往这个列表中set元素,由于java父类型可以医用子类型,所有Number任何的子类型都可以设置进去。想象一下,这个方法往List中set原始的代码,是否也同样适用于List<Object>,其实任何Number的父类都适合,那怎么把泛型类型是Number的父类的list传递到这个方法呢?把方法的入参声明成List<? super Number>就可以达到这个目的
List<? extend Number>和List<? super Number>的区别:
List<? extend Number>为取出元素而生,List<? super Number>为设置进元素而生,在Effective Java一书中,把这一原则称为:PECS原则。