1. 程式人生 > >effectiveJava學習筆記:泛型(一)

effectiveJava學習筆記:泛型(一)

先給大家列出需要的術語

在新程式碼中(jdk1.5以後)不要使用原生態的型別。

為什麼會有泛型 list<E>

如果沒有泛型的話,我們從一個沒有定義型別的集合裡面取資料的時候就不知道是什麼型別,強制轉換會出現ClassCastException異常

這時候原生態型別就需要升級->泛型,有了泛型的規約這種情況就會避免了

簡單說來,就是在執行前即可發現錯誤。

原生態的List和引數化的型別List<Object>之間有什麼區別呢?不嚴格的講,前者逃避了泛型檢查,後者明確告訴編譯器,它能夠持有任意型別的物件。雖然可以將List<String>傳遞給型別為List的引數,但是不能將它傳給型別為List<Object>的引數。

// Use raw type (List) - fails at runtime!
public static void main(String[] args) {
    List<String> strings = new ArrayList<String>();
    unsafeAdd(strings, new Integer(42));
    String s = strings.get(0); // Compiler - generated cast
}

private static void unsafeAdd(List list, Object o) {
    list.add(o);
}

Set<?>:無限制的萬用字元型別(unbounded wildcard type)

如果要使用泛型,但不確定或者不關心實際的型別引數,就可以使用一個問號代替

總結:

Set<Object>是個引數話型別,表示可以包含任何物件型別的一個集合;

Set<?>則是一個萬用字元型別,表示只能包含某種未知物件型別的一個集合;

Set則是個原生態型別,它脫離了泛型系統。

前兩種是安全的,最後一種不安全。

我們常常在原始碼中看到的Java泛型中的標記符含義: 

 E - Element (在集合中使用,因為集合中存放的是元素)

 T - Type(Java 類)

 K - Key(鍵)

 V - Value(值)

 N - Number(數值型別)

? -  表示不確定的java型別

消除非受檢警告

         在使用泛型時,使用編譯器完成程式碼編寫的時候,可能會有黃色的波浪線提示警告,不要忽略它,每一處警告可能都是一個ClassCastException。

        可以使用@SuppressWarnings("uncheched")消除警告,這個宣告可以作用的範圍十分廣泛,類、方法、變數上都可以,儘可能的使作用範圍小一些,在宣告這個註解的時候最好加上註釋,註明理由為什麼這裡是安全無須檢查?

       但是在使用@SuppressWarnings("uncheched")時,必須確保程式碼的正確

 public <T> T[] toArray(T[] a){
        if(a.length < size){
            T[] result=(T[])Arrays.copyOf(elements,size,a.getClass());
            return result
        }
        System.arraycopy(elements,0,a,0,size);
        if(a.length > size)
            a[size] = null;
        return a;
    }


public <T> T[] toArray(T[] a) {
        if (a.length < size) {
            @SuppressWarning("unchecked")
            T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass());
            return result;
        }
        System.arraycopy(elements, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

列表優先於陣列

一般來說,陣列和泛型不是很好的能混合使用,在使用泛型的時候優先使用列表

具體原因有:

1、陣列是協變的,泛型是不可變的。

什麼是協變? 如果Sub是Super的子型別,那麼陣列型別Sub[] 就是Super[]子型別。 
什麼是不可變? 對於任意兩個不同型別的type1和type2,List< type1 >既不是List< type2 >的子型別,也不是List< type2 >的超型別。 
那麼你可能會覺得泛型是有缺陷的,恰恰相反,有缺陷的是陣列。 
下面程式碼是合法的:

//Fails at runtime
Object[] objectArray=new Long[1];
ObjectArray[0]="I don't fit in";//Throws ArrayStoreException

下面的程式碼是不合法的:

//Won't compile
List<Object> o1=new ArrayList<Long>();//Incompatible types
o1.add("I don't fit in")

其實都是錯誤的,但是陣列只有在執行時才會報錯。列表在編譯時就會報錯。

2.陣列是具體化的,泛型是通過擦除來實現的。

陣列是具體化的(reified)。因此陣列會在執行時才知道並檢查他們的元素型別約束。泛型是通過擦除來實現的。因此泛型只在編譯時強化他們的型別資訊,並在執行時丟棄(或者擦除)他們元素的型別資訊。

建立泛型陣列是非法的:

//Cannot create a generic array of List<String>
List<String>[] stringLists = new List<String>[1];