8泛型
定义泛型类
1 | public class Pair<T> |
泛型方法
1 | class ArrayAlg |
double middle = ArrayAlg.getMiddle(3.14, 1729, 0);
编译器将会自动打包参数为 1 个Double 和 2 个 Integer 对象,而后寻找这些类的共同超类型。事实上;找到 2 个这样的超类型:Number 和 Comparable 接口,其本身也是一个泛型类型。在这种情况下,可以采取的补救措施是将所有的参数写为 double 值。
类型变量的限定
类在前,接口在后
T extends Comparable & Serializable
泛型代码与虚拟机
类型擦除
翻译泛型表达式
翻译泛型方法
调用遗留代码
约束与局限性
不能使用基本类型实例化类型参数
没有 Pair
原因是类型擦除。擦除之后,Pair类含有Object类型的域,而Object不能存储 double值。原因:与 Java 语言中基本类型的独立状态相一致。
运行时类型查询只适用于原始类型
只会检查类型是否是Pair不会检查泛型,如下示例
1 | if (a instanceof Pair<String>) //Error |
1 | List<String> stringList = Arrays.asList("1", "2"); |
不能创建参数化类型的数组
Pair<String>[] table = new Pair<String>[10]; // Error
可以声明类型为 Pair<String>[]
的变量 但不能用new Pair<String>[10]
初始化这个变量
如果需要收集参数化类型对象, 只有一种安全而有效的方法:使用 ArrayList:ArrayList<Pair
不能实例化类型变置
public Pair() { first = new T(); second = new T(); } // Error
解决办法:提供一个构造器表达式,通过反射调用 Clasmewlnstance 方法来构造泛型对象
1 | public static <T> Pair<T> makePair(Class<T> cl) |
不能构造泛型数组
T[] arr = new T[10];// ERROR
解决办法:
1 | class MyClass<T> { |
泛型类的静态上下文中类型变量无效
以下代码无效。
禁止使用带有类型变量的静态域和方法
1 | public class Singleton<T> |
不能抛出或捕获泛型类的实例
泛型类型不可扩展 Exception,throwable
1 | public class Problem<T> extends Exception { // ERROR |
catch 子句中不能使用类型变量
1 | try {} |
可以消除对受查异常的检查
1 | ArrayList<Parent1> aa = new ArrayList<Sun2>();// ERROR |
继承规则
无论 S 与 T 有什么联系,通常,Pair<S>与Pair<T>没有什么关系
通配符类型
通配符概念
Pair<? extends Employee〉
1 | Pair<PParent> pair = new Pair<>(new PSun(), new PSun()); // OK |
通配符的超类型限定
指定一个超类型限定(supertypebound):? super Manager
限定符包含自己
超类限定符 ?supper getter方法受限
子类限定符 ?extends setter方法受限
无限定通配符
例如,Pair>
类型 Pair> 有以下方法:(伪代码)? getFi rst()
void setFirst⑺
getFirst 的返回值只能赋给一个 Object。setFirst 方法不能被调用, 甚至不能用 Object 调用。可以调用set(null)
用途例如:
1 | public static boolean hasNulls(Pair<?> p) |
上例中 通配符的版本可读性更强
问题
怎么理解:Pair<?> 和 Pair 本质的不同在于: 可以用任意 Object 对象调用原始 Pair 类的 setObject方法。
反射和泛型
反射允许你在运行时分析任意的对象。如果对象是泛型类的实例,关于泛型类型参数则得不到太多信息,因为它们会被擦除。