不能初始化泛型引數和陣列
阿新 • • 發佈:2019-01-09
泛型型別在編譯期被擦除,我們在類初始化時將無法獲得泛型的具體引數,比如這樣的程式碼:
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的原始碼就清楚了,程式碼如下:
注意elementData的定義,它容納了 ArrayList的所有元素,其型別是Object陣列,因為Object是所有類的父類,_陣列又允許協變(Covariant),因此elementData陣列可以容 納所有的例項物件。元素加入時向上轉型為Object型別(E型別轉為Object),取出時向下 轉型為E型別(Object轉為E型別),如此處理而已。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]; } }
在某些情況下,我們確實需要泛型陣列,那該如何處理呢?程式碼如下:
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就會解決問題。
類的成員變數是在類初始化前初始化的,所以要求在初始化前它必須具有明確的型別, 否則就只能宣告,不能初始化。