Effective Java中的泛型部分
今天將Effective Java(第二版)中的泛型部分讀完,深感自己泛型掌握有多麽不熟練,還是需要多加練習。
廢話少說,上點重點:
1.不要使用原型
比如:
List list = new ArrayList();
當你用該list引用指向其他帶有泛型的List時,是不會出現編譯錯誤的,只會給一個rawtype的警告,但是————
這很容易出現掛羊頭賣狗肉的情況,比如你指向了一個List<Integer>,卻add了一個String,這不會出現任何編譯錯誤,但
當你取出來轉成Integer時就會出現ClassCastException,因為你根本存的就是一個String...
如果你不確定類型,那麽請使用“?”這種通配符,可以消除警告,並且阻止除null外的一切元素添加。
2.優先考慮列表,而不是數組
原因很簡單,數組是可協變的,泛型不是。比如,你有一個List<String>[]數組(假設合法),如果你用一個Object[]引用指向了這個泛型數組,
這肯定可以,因為數組是可協變的,但是當你從Object[]中取出這個元素,並調用get方法返回Integer時,就會出現類型轉換的異常。所以,泛型
數組是非法的。
3.優先考慮泛型及泛型方法
這個不用多說,自己可以看看集合類的源碼,基本上都是使用了泛型,對於數組存儲這塊,應該是利用反射,用Arrays.newInstance()方法生成一個
Object引用的數組,然後再強制轉換為T[]的數組,這樣可以保證在add或者get時,類型的正確性(編譯器幫你搞定)。
泛型方法是非常強大的方法:
public static <T> void swap(List<T> list, int i, int j)
這種泛型方法,可以自動捕獲異常,包括你傳入的參數為List<?>時也可以,只不過這時候捕獲的為?這種通配符,建議只在void方法中使用。
4.PECS原則
即T的生產者(producer)泛型為<? extends T>,T的消費者(consumer)泛型為<? super T>。
原因很簡單,生產者主要提供的方法為get()方法,而Java在運行時泛型是被擦除的,也就是這裏的T變為了Object,
在調用或離開方法的“邊界處”,編譯器會按照泛型參數T轉型,也就是說,調用生產者get方法所獲取的對象類型,都被一致
地轉為T類型,表明不論是什麽類型,獲取出來只要T類型能接就可以了(為T的子類型)。消費者主要提供的方法為add()
(或者其他的什麽consume()等等),這時表明消費者消費的類型只要是T的父類型即可,這是調用add()方法時,所消費的對象
均為T或T的父類型,保證了下限。
總結:要更好的理解泛型,必須多動手去練,去思考,抓住泛型在運行時是被擦除這一特點,就能掌握大部分泛型的使用了
Effective Java中的泛型部分