1. 程式人生 > >不能初始化泛型引數和陣列

不能初始化泛型引數和陣列

泛型型別在編譯期被擦除,我們在類初始化時將無法獲得泛型的具體引數,比如這樣的程式碼:

class Foo<T>{
 private T t =new T();
 private T[] tArray=new T[5];
 private List<T> list= new ArrayList<T>();
}

這段程式碼有什麼問題呢? t、tArray、list都是類變數,都是通過new聲明瞭一個型別, 看起來非常相似啊!但這段程式碼是編譯通不過的,因為編譯器在編譯時需要獲得T型別,但 泛型在編譯期型別已經被擦除了,所以new T()和new T[5]都會報錯(可能有讀者疑惑了 : 泛型型別可以擦除為頂級類Object,那T型別擦除成Object不就可以編譯了嗎?這樣也不 行,泛型只是Java語言的一部分,Java語言畢竟是一個強型別、編譯型的安全語言,要確保執行期的穩定性和安全性就必須要求在編譯器上嚴格檢査)。可為什麼new Arra

yList<T>()卻 不會報錯呢?

這是因為ArrayList表面是泛型,其實已經在編譯期轉型為Object 了,我們來看一下 ArrayList的原始碼就清楚了,程式碼如下:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
   //容納元素的陣列
   private transient Object[] elementData;
    //建構函式
    public ArrayList() { 
       this(10);
     }
   //獲得一個元素
   public E get(int index) {
    RangeChecM (index);
  //返回前強制型別轉換
    return (E) elementData[index];
}
}
注意elementData的定義,它容納了 ArrayList的所有元素,其型別是Object陣列,因為Object是所有類的父類,_陣列又允許協變(Covariant),因此elementData陣列可以容 納所有的例項物件。元素加入時向上轉型為Object型別(E型別轉為Object),取出時向下 轉型為E型別(Object轉為E型別),如此處理而已。

在某些情況下,我們確實需要泛型陣列,那該如何處理呢?程式碼如下:

 private T t;
  private T[] tArray;
  private List<T> list=new ArrayList<T>();
  
  public Foo() {
	try {
		Class<?> tType=Class.forName("");
		t=(T) tType.newInstance();
		tArray=(T[]) Array.newInstance(tType, 5);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

此時,執行就沒有任何問題了。剩下的問題就是怎麼在執行期獲得T的型別,也就是 tType引數,一般情況下泛型型別是無法獲取的,不過,在客戶端呼叫時多傳輸一個T型別 的class就會解決問題。

類的成員變數是在類初始化前初始化的,所以要求在初始化前它必須具有明確的型別, 否則就只能宣告,不能初始化。