泛型程序设计
1.类型参数的好处
不需要强制类型转换,编译器会检查,防止你插入错误类型的对象
2.定义简单泛型类
泛型类就是有一个或者多个类型变量的类,
泛型类可以有多个类型变量,Pair类的第一个和第二个字段是由不同的类型
类型变量在整个类定义中用于指定方法的返回类型以及字段和局部变量的类型
可以用具体的类型替换类型变量来实例化泛型类型
工厂方法:不用新建对象而给出实例
3.泛型方法
可以定义一个带有类型参数的方法
这个方法在普通类中定义,是一个泛型方法,类型变量放在修饰符的后面,在返回类型前面。
调用一个泛型类方法时,把具体类型包围在尖括号中,放在方法名前面
方法调用可以省略<String>类型参数,编译器可以推断
4.类型变量的限定
可以对类型变量设置一个限定
表示T是限定类型的子类型,T和限定类型可以是类,也可以是接口。写在返回类型之前
一个类型变量或通配符可以有多个限定,用&分隔
按照Java继承机制,可以根据需要拥有多个接口超类型,但最多有一个限定可以是类,如果有一个类作为限定,它必须是限定列表中的第一个限定。
5.泛型代码和虚拟机
虚拟机没有泛型类型对象-所有对象都属于普通类
类型擦除
无论何时定义一个泛型类型,都会自动提供一个相应的原始类型,其名字就是去掉类型参数的泛型类型名,类型变量会被擦除,并替换为其限定类型,对于无限定类型的变量则替换为Object。
原始类型用第一个限定来替换类型变量。
转换泛型表达式
编写一个泛型方法调用时,擦出了返回类型,编译器会插入强制类型转换
字段也是
转换泛型方法
类型擦除也会出现在泛型方法中
虚拟机没有泛型,只有普通类和方法
所有的类型参数都会替换为它们的限定类型
会合成桥方法来保持多态
为保持类型安全性,必要时会插入强制类型转换
调用遗留代码
设计泛型时,主要目标是允许泛型代码和遗留代码之间能够互操作。
限制与局限性
讨论使用Java泛型时需要考虑的一些限制,大多数都是由类型擦除引起的
1.不能用基本类型实例化类型参数
2.运行时类型查询只适用于原始类型
如果试图查询一个对象是否属于某个泛型类型,会得到编译错误(instanceof)或警告(强制类型转换时)
3.不能创建参数化类型的数组
不允许创建这些数组,声明类型为Pair<String>[]变量仍然合法,不过不能用new初始化
4.Varargs警告
5.不能实例化类型变量
6.不能构造泛型数组
7.泛型类的静态上下文中类型变量无效
不能在静态字段或方法中引用类型变量
8.不能抛出或捕获泛型类的实例
泛型类扩展Throwable是不合法的
catch子句中不能使用类型变量,但是在异常规范中使用类型变量是允许的
9.可以取消对检查型异常的检查
Java异常处理的一个基本原则是,必须为所有检查型异常提供一个处理器,可以利用泛型取消这个机制。
10.注意擦除后的冲突
擦除泛型类型后,不允许创建引发冲突的条件,补救方法是重新命名引发冲突的方法。为了支持擦除转换,我们要施加一个限制:倘若两个接口类型是同一接口的不同参数化,一个类或类型变量就不能同时作为这两个接口类型的子类。
泛型类型的继承规则
总是可以将参数化类型转换为一个原始类型
通配符类型
1.概念
在通配符类型中,允许类型参数变化
区分安全的访问器和不安全的更改器方法
2.通配符的超类限定
你可以指定一个超类型限定
这个通配符限制为Manager的所有超类型
带有超类型限定的通配符允许你写入一个泛型对象,而带有子类型限定的通配符允许你读取一个泛型对象。
3.无限定通配符
4.通配符捕获
通配符不是类型变量,不能用?作为一种类型的代码,下面代码是非法的
swapHelper方法的参数T捕获通配符
反射与泛型
反射允许你在允许时分析任意对象
1.泛型Class类
Class类是泛型类,String.class实际上是一个Class<String>类的对象