本文是对 java 泛型的总结
泛型
泛型类与方法的一般格式
泛型类:
public class Pair<T> |
泛型方法:
class ArrayAlg |
该方法是在普通类定义的泛型方法,调用时:
String middle = ArrayAlg.<String>getMiddle("]ohnM, "Q.n, "Public");
术语:
ArrayList<E>
– 泛型类型ArrayList
– 原始类型E
– 类型参数(变量)<>
– 读作”typeof”ArrayList<Integer>
– 参数化的类型Integer
– 实际类型参数
类型变量的限定
我们可以对类型变量加以约束,毕竟我们很难适用每种泛型。可以通过对类型变量 T 设置限定(bound) 实现这一点,格式如下:
<T extends BoundingType>
BoundingType 可以是
- 类:T 是它的子类型(subtype)
- 接口: T 是实现了该接口的类
可以有多个接口,当然至多有一个类,用 “&” 分隔。
ps: 由于类型擦除机制,为了提高效率,应该将标签(tagging) 接口 (即没有方法的接口)放在边界列表的末尾。
泛型转化的内部
- 虚拟机中没有泛型, 只有普通的类和方法;所有的类型参数都用它们的限定类型替换。
- 编译器在调用泛型方法时会自动插入强制类型转换。
- 桥方法被合成来保持多态。
约束与局限性
- 不能用基本类型实例化类型参数
即没有Pair<double>
,只有Pair<Double>
。原因是类型擦出后,Object不能存储double值,毕竟它不是对象
- 运行时类型查询只适用于原始类型
所有的类型查询只产生原始类型,例子:
Pair<String> stringPair = ...; |
- 不能创建参数化类型的数组
Pair<String>[] table
是错的;
只能使用AllayList: ArrayList<Pair<String>> table
- Varargs警告
向参数个数可变的方法传递一个泛型类型的实例时,为了调用这个方法,Java 虚拟机必须建立一个参数化类型的数组,可是这违反了前一个规则。
我们可以用 @SafeVarargs 直接标注该方法,这样就能正常运行。
- 不能实例化类型变量
例如:
public Pair() { first = new T(); second = new T(); } // Error
-
不能构造泛型数组
-
泛型类的静态上下文中类型变量无效
也就是不能在静态域或方法中引用类型变量。
- 不能抛出或捕获泛型类的实例
- 可以消除对受查异常的检查