泛型

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 域。 因此, 禁止使用带有类型变量的静态域和方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章