1. 类型擦除
虚拟机中没有泛型,只有普通的类和方法。定义一个泛型类型,会进行类型擦除,如:
public class Pair<T>
{
private T first;
private T second;
public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}
会被擦除为:
public class Pair<T>
{
private Object first;
private Object second;
public Pair() { first = null; second = null; }
public Pair(Object first, Object second) { this.first = first; this.second = second; }
public Object getFirst() { return first; }
public Object getSecond() { return second; }
public void setFirst(Object newValue) { first = newValue; }
public void setSecond(Object newValue) { second = newValue; }
}
2. 类型翻译
当程序调用泛型方法时,编译器插入强制类型转换。如
Pair<Employee> buddies = ...;
Employee buddy = buddies.getFirst();
擦除 getFirst 的返回类型后将返回 Object 类型。编译器自动插入 Employee 的强制类型转换。也就是说,编译器把这个方法调用翻译为两条虚拟机指令:
- 对原始方法 Pair.getFirst 的调用。
- 将返回的 Object 类型强制转换为 Employee 类型。
3. 泛型的限制
-
不能用基本类型实例化类型参数。因此,没有 Pair< double>, 只 有 Pair< Double >。 其原因是类型擦除。擦除之后,Pair 类含有 Object 类型的域, 而 Object 不能存储 double 值。
-
运行时类型查询只适用于原始类型。
if (a instanceof Pair<String>) // Error
实际上仅仅测试 a 是否是任意类型的一个 Pair。同样的道理, getClass 方法总是返回原始类型。Pair<String> stringPair = . . Pai「< Employee〉employeePair = . . if (stringPair.getClassO == employeePair.getClassO) // they are equal
-
不能实例化参数化类型的数组。数组会记住它的元素类型, 如果试图存储其他类型的元素, 就会抛出一个 ArrayStoreException 异常,对于泛型类型,擦除会使这种机制无效。
Pair<String>[] table = new Pair<String>[10]; // Error Object[] objarray = table; objarray[0] = new Pair<Employee>();//能够通过数组存储检查
需要说明的是, 只是不允许创建这些数组, 而声明类型为 Pair< String>[] 的变量仍是合法的。不过不能用 new Pair< String>[10] 初始化这个变量。
-
泛型类的静态上下文中类型变量无效。不能在静态域或方法中引用类型变量。
public class Singleton<T> { private static T singlelnstance; // Error public static T getSinglelnstanceO // Error { if (singleinstance == null) construct new instance of T return singlelnstance; } }
如果这个程序能够运行, 就可以声明一个 Singleton< Random> 共享随机数生成器, 声明一个 Singleton< JFileCh00Ser> 共享文件选择器对话框。 但是, 这个程序无法工作。类型擦除之后, 只剩下 Singleton 类, 它只包含一个 singlelnstance 域。 因此, 禁止使用带有类型变量的静态域和方法。