[改善Java代碼]不能初始化泛型參數和數組


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

class Foo<T>{
    //private T t =new T();//報錯Cannot instantiate the type T
    //private T[] tArray= new T[5];//報錯Cannot create a generic array of T
    private List<T> list= new ArrayList<T>();
}

這段代碼有什么問題?

t,tArray,list都是類變量,都是通過new聲明了一個類型,看起來非常的相似.

但是這段代碼是通不過的,因為編譯期在編譯時需要獲得T類型,但是泛型在編譯期類型已經被擦除了,所以new T()和new T[5] 都會報錯,

但是你也許會認為,泛型類型可以擦除為頂級的Object類,那T類型擦除成Object不就可以編譯了?

這樣也不行,泛型只是Java語言的一部分,Java語言畢竟是一種強類型,編譯型的安全語言,要確保運行期的穩定性和安全性就必須要求在編譯器上嚴格檢查.

但是為什么new ArrayList<T>()卻不會報錯呢?

這是因為ArrayList表面上是泛型,其實已經在編譯期轉型為了Object類型了,要看一下ArrayList的源代碼就清楚了.

 1 public class ArrayList<E> extends AbstractList<E>
 2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
 3     /**
 4      * The array buffer into which the elements of the ArrayList are stored.
 5      * The capacity of the ArrayList is the length of this array buffer.
 6      */
 7     private transient Object[] elementData;
 8     /**
 9      * Constructs an empty list with an initial capacity of ten.
10      */
11     public ArrayList() {
12         this(10);
13     }    
14         
15     /**
16      * Returns the element at the specified position in this list.
17      *
18      * @param  index index of the element to return
19      * @return the element at the specified position in this list
20      * @throws IndexOutOfBoundsException {@inheritDoc}
21      */
22     public E get(int index) {
23         rangeCheck(index);
24 
25         return elementData(index);
26     }
27     E elementData(int index) {
28         return (E) elementData[index];
29     }        
30 }

 

 注意看elementData定義,它容納了ArrayList的所有元素,其類型是Object數組,因為Object是所有類的父類,數組又允許協變(Covariant),因此elementData數組可以容納所有的實例對象.

元素加入時向上轉型為Object類型(E類型轉變為Object),取出時向下轉型為E類型(Object轉為E類型).

在某些情況下,我們確實需要泛型數組,怎么處理?

 1 import java.lang.reflect.Array;
 2 import java.util.ArrayList;
 3 import java.util.List;
 4 
 5 public class Client {
 6     public static void main(String[] args) {
 7         
 8         
 9     }
10 }
11 
12 class Foo<T>{
13     //不再初始化,由構造函數初始化
14     private T t;
15     private T[] tArray;
16     private List<T> list= new ArrayList<T>();
17     //構造函數初始化
18     public Foo(){
19         try {
20             Class<?> tType = Class.forName("");
21             t = (T)tType.newInstance();
22             tArray = (T[])Array.newInstance(tType,5);
23         } catch (Exception e) {
24             e.printStackTrace();
25         }
26     
27     }
28 }

 

此時運行就沒有任何問題了,剩下的問題就是怎么在運行期獲得T的類型.也就是tType參數.一般情況下泛型類型是無法獲取的,不過在客戶端調用時多傳輸一個T類型的class就會解決問題.

類的成員變量是在類初始化前初始化的,所以要求在初始化前它必須具有明確的類型.否則就只能聲明,不能初始化.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM