Java通配符的使用
基本介绍
泛型是一种表示类或者方法行为对于未知类型的类型约束的方法,通配符在类型系统中有重要的作用,它们为一个泛型类所指定的类型集合提供了一个有用的类型范围。
协变
数组是协变的,因为Integer是Number的子类型,数组类型Integer[]是Number[]的子类型,因此在任何需要 Number[]值的地方都可以提供一个Integer[]值。泛型不是协变的,List<Integer>不是List<Number>的子类型。
因此这种代码无法通过编译:
1 | ArrayList<Fruit> flist = new ArrayList<Apple>(); |
使用通配符
我们知道上面那种语句是无法通过编译,通过它们之间存在父子类型的关系,如果我们需要建立这种向上转型的关系,就需要使用通配符了。
上边界限定通配符
利用 <? extends Fruit>
形式的通配符,可以实现泛型的向上转型:
1 | public class GenericsAndCovariance { |
在这种情况下,我们不知道这个 List 到底持有什么类型,因此也不可能安全的添加一个对象,唯一可以添加的是null。编译器会为这个问号类型起一个临时的代号,比如CAP#1。但是调用某个返回Fruit的方法就是安全的,因此不管实际类型是什么,肯定能够转型为Fruit。
1 | public class CompilerIntelligence { |
下边界限定通配符
这是通配符的另一个方向,超类型的通配符:? super T,T是类型参数的下界。在这种情况下,写入是有效的,因为对象都可以被向上转型成合法的类型:
1 | public class SuperTypeWildcards { |
无边界通配符
还有一种通配符是无边界通配符,它的使用形式是一个单独的问号:List<?>,也就是没有任何限定。因为不知道是具体哪种类型,我们也无法向其中添加对象。
类型参数与无边界通配符
List<T>是泛型方法,List<?>是限制通配符。一般来说,List<T>一般有两种用:定义一个通用的泛型方法和限制方法的参数之间或参数和返回结果之间的关系。
比如这种情况就可以限制返回结果的类型与参数类型一致:
1 | List<T> getList<T param1,T param2> |
而List<?>一般就是在泛型起一个限制作用。
当对已经存在的泛型,我们不想给她一个具体的类型做为类型参数,我们可以给其一个不确定的类型作为参数。这个就是通配符的意义。
Reference
https://segmentfault.com/a/1190000005337789
https://www.zhihu.com/question/31429113