Java 泛型学习一 泛型概念
Java 泛型学习二 泛型的限制
Java 泛型学习三 通配符
Java 泛型学习四 自动擦除
Java 泛型学习五 泛型擦除带来的不自然
Java 泛型学习六 泛型类型系统
在Java语言中,类型系统描述了不同类型之间的转换关系。如果一个类型是另一个类型的子类型,俺们从子类型到父类型的转换是自动进行的,而从父类型到子类型的转换需要再代码中显示进行,这是因为从父类型到子类型的转换可能是不安全的,需要由开发人员显示进行。
在泛型被引入之前,Java中的父类型和子类型的关系主要通过类继承和接口实现机制来声明。但泛型的引入对Java语言中登录诶性系统产生了比较大的影响。这是因为泛型类型的实例化形式中包含了所使用的实际类型,这些类型之间也可以有父子类型关系。这相当于把类型系统从之前的一维结构扩展为二维结构:泛型类型本身和参数化类型的实际类型。我们来分六种情况看下他们的关系。
1. 第二维(参数化类型的实际类型)完全相同
当两个参数化类型的实际类型完全相同时,两个类型的父子类型取决于泛型类型本身的父子关系。如ArrayList<Number>和List<Number>,取决于ArrayList类和List接口之间的父子关系,而ArrayList是List接口的实现,所以ArrayList<Number>是List<Number>的子类型。
2. 第一维(泛型类型)完全相同
如果泛型类型相同,在实例化时使用的是不包含通配符的两个不同具体类型,则这两个类型之间不存在任何父子关系,如 ArrayList<Integer> 和 ArrayList<Number>不存在任何父子关系。这一点比较难理解,因为Integer是Number的子类,其实这主要是从安全的角度去考虑的。请看示例代码:
package net.oseye; import java.util.ArrayList; public class FanXing { public static void main(String[] args) { new FanXing().changeList(); } public void modify(ArrayList<Number> list){ list.add(1.0f); //添加一个Float类型对象 } public void changeList(){ ArrayList<Integer> list=new ArrayList<Integer>(); list.add(3); modify(list); //编译不通过 } }
如果ArrayList<Integer> 是 ArrayList<Number>的子类,上面的代码将会抛出运行时异常。
3. 无界通配符
无界通配符表示的是全集,包含所有其他的集合,例如List<?>是所有List泛型类的实例化形式父类型,List<String>、List<? extends Number>和List<? super Integer>都是List<?>的子类型。
4. 有界通配符
有界通配符的类型系统取决于它的上界和下届。
- 上界通配符表示的是上界类型及其子类型的集合;
- 下界通配符和上界通配符的表示的父子关系正好相反;
例如
- 上界通配符:"? extends A"和"? extends B"之间的关系取决于类型A和B之间的关系,如果A是B的子类型,那么"? extends A"是"? extends B"的子集,也即是子类型;
- 下界界通配符:"? super A"和"? super B"之间的关系取决于类型A和B之间的关系,如果B是A的子类型,那么"? super A"是"? super B"的子集,也即是子类型;
5. 原始类型
一个泛型类型的所有实例化形式都是其对应的原始类型的子类型,如List<String>和List<? extends Number>都是List的子类型,这种设计目的的为了与不使用泛型的遗留代码进行交互。
6. 复杂类型
对于比较复杂的类型判断时,可以根据上面规则从简单的情况开始考虑,比如,在判断ArrayList<Integer>和Collection<? extends Number>之间的关系时,先考虑到ArrayList<Integer>是Collection<Integer>的子类型,而Collection<Integer>是Collection<? extends Number>的子类型,所以ArrayList<Integer>是Collection<? extends Number>的子类型。
在参数化类型的单个类型中也可以多次使用通配符,如在List<? extends List<? extends Number>>的类型声明中使用了两个上界通配符作为实际的类型。对于这种情况的类型判断比较复杂,基本思路是按照递归的方式一次进行判断,从最内层的类型开始进行判断。比如,对于List<? extends List<Integer>>和List<? extends List<? extends Number>>这两个类型,具体的判断过程是:Integer类型是"? extends Number"的子类型,进而可知List<Integer>是List<? extends Number>的子类型。而List<Integer>和List<? extends Number>作为上届出现,因此List<? extends List<Integer>>是List<? extends List<? extends Number>>的子类型。