第八章 泛型程序设计
泛型方法
class ArrayAlg{
public static <T> T getMiddle(T... a){
return a[a.length / 2]
}
}
当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型。类型变量放在修饰符的后面,返回类型的前面。
String middle = ArrayAlg.<String>getMiddle("J","k","L")
类型变量的限定
public static <T extends Comparable> T func(T[] a){...}
这个泛型方法规定了 T 必须实现 Comparable (Comparable本身也是一个泛型类型)接口。此方法只能被实现了Comparable接口的类(如String,localDate)的数组调用。否则会编译报错。
一个类型变量或通配符可以有多个限定
T extends Comparable & Serializable
翻译泛型方法
- 虚拟机中没有泛型,只有普通的类和方法。
- 所有的类型参数都用他们的限定类型替换
- 桥方法被合成来保持多态。
- 为保持类型安全性,必要时插入强制类型转换。
约束与局限性
-
不能有基本类型实例化类型参数
没有Pair<double>,只有Pair<Double>
-
运行时类型查询只适用于原始类型
if (a instanceof Pair<String>) // Error Pair<String> p = (Pair<String>) a // Warning ---can only test that a is a Pair 同样的道理,getClass总是返回原始类型 Pair<String> stringPair = ..... Pair<Employee> employeePair = ... if (StringPair.getClass()==employeePair.getClass()) 结果为true,因为两次调用getClass豆浆返回Pair.class
-
不能创建参数化类型的数组
因为对于泛型类型,擦除会使类型参数无效。能够通过数组存储检查,但是会导致一个类型错误。
Pair<String> table = new Pair<String>[10] // Error
-
不能实例化类型变量
public Pair() { first = new T(); second = new T(); } // error
类型擦除会将T改变成Object,而且本意不希望调用new Object。
-
不能构造泛型数组
public static <T extends Comparable> T[] minmax(T[] a){T[] mm = new T[2]} // Error 当类型擦除时,Object[]引用赋给Comparable[]时,会发生ClassCastException
-
泛型类的静态上下文中类型变量无效
public class Singleton<T>{ private static T singleInstance // Error public static T getSingleInstance // error { if (singleInstance == null) { return singleInstance } } }
类型擦除后,只有一个Singleton类,只包含一个singleInstance域,因此禁止使用带有类型变量的静态域和方法。
-
不能抛出或捕获泛型类的实例
public class Problem<T> extends Exception {} // Error catch中不能使用类型变量。
通配符类型
如果要编写一个答应雇员的方法:
public static void printBuddies(Pair<Employee> p){}
由于Pair<Employee>和Pair<Manager>没有什么联系,所以并不能将Pair<manager>传递
使用通配符类型
public static void printBuddies(Pair<? extends Employee> p){}
-
无限定通配符
Pair<?> 和 Pair有很大不同 Pair<?>有?get 和 void set方法 get方法返回值只能赋值给一个Object,set方法不能被调用。 两者本质区别是Pair<?> 可以用任意Object对象调用原始Pair类的setObject方法