雖是讀書筆記,可是如轉載請註明出處http://segmentfault.com/blog/exploring/
..拒絕伸手複製黨java
Java泛型核心概念: 告訴編譯器想使用什麼類型,而後編譯器幫你處理一切細節。segmentfault
泛型的主要目的:數組
泛型不能作什麼:不能顯示地引用運行時類型操做,例如轉型,instanceof and new表達式。(由於擦除)安全
可變參數(T ... args)與泛型方法(makelist實現util.Arrays.asList方法相同的功能)
用於Generator的泛型方法: 使用泛型方法建立Generator對象,大大減小了咱們要編寫的代碼dom
javapublic BasicGenerator(Class<T> type){ this.type = type; } public T next(){ try{ return type .newInstance(); } catch(Exception e){ throw new RuntimeException(e); } } }
簡化元組的使用 : 經過使用泛型方法整個各個Tuple類,重載static方法建立元組工具
javapublic class Tuple { public static <A,B> TwoTuple<A,B> tuple(A a, B b) { return new TwoTuple<A,B>(a, b); } public static <A,B,C> ThreeTuple <A,B,C> tuple(A a, B b, C c) { return new ThreeTuple<A,B,C>(a, b, c);} public static <A,B,C,D> FourTuple<A,B,C,D> tuple(A a, B b, C c, D d) { return new FourTuple<A,B,C,D>(a, b, c, d); } }
一個Set實用工具this
使用泛型能夠簡單而安全的建立複雜模型code
Java泛型是經過擦除來實現的,namley 在使用泛型的時候,任何具體的類型信息都被擦除了,你惟一知道的就是你在使用一個對象。對象
在java泛型代碼內部,沒法得到任何有關泛型參數類型的信息。所以,你沒法知道用來建立某個特定實例的實際的類型參數。好比List和List在運行時是相同的類型。blog
擦除的正當理由是從非泛華代碼到泛華代碼的轉變過程,以及不破壞現有類庫的狀況下,將泛型融入Java語言。擦除使得現有的非泛型客戶端代碼可以在不改變的狀況下繼續使用,直至客戶端準備好用泛型重寫這些代碼。
邊界處的動做: 非泛型和泛型版本的類似的兩個類經過javap -c 命令反編譯能夠發現字節碼是相同的,就是說在運行時使用泛型的代碼和普通代碼沒有什麼區別。泛型中的全部動做都發生在邊界處—對傳遞進來的值進行額外的編譯期檢查,並插入對傳遞出去的值的轉型。這有助於澄清對擦除的混淆,所謂邊界,就是發生動做的地方。
泛型不能作:
instanceof
解決方法:使用類型標籤,利用動態的isInstance判斷
javapublic class ClassTypeCapture<T> { Class<T> kind; //類型標籤 public ClassTypeCapture(Class<T> kind){ this.kind = kind; } }
泛型不能作:new表達式
解決方法:傳遞一個顯示的工廠對象,限制其類型,使得只能接受實現這個工廠的類。
javapublic interface FactoryI<T> { T create(); } public class Foo2<T> { private T x ; //工廠 public <F extends FactoryI<T>> Foo2(F factory){ x = factory.create(); } public static void main(){ new Foo2<Integer>(new IntegerFactory()); new Foo2<Widget>(new Widget.Factory()); } }
泛型不能作:建立數組 T[] array
解決方法: 想要建立泛型數組的時候都使用ArrayList. orz...或者使用類型標記
若是實在想建立泛型數組,那麼惟一方式就是建立一個被擦除類型的新數組(對象數組),而後對其轉型。
javapublic class GenericArray<T> { private T[] array ; public GenericArray(int sz){ //建立一個對象數組,而後對它轉型 array = (T[])new Object[sz] ; } }
可是這樣並非很好,由於有了擦除,數組運行時候類型就只能是Object[],若是在建立時候對其轉型爲T[],那麼編譯器該數組的實際類型就會丟失,而編譯器可能會錯過潛在的錯誤檢查。因此最爲可靠的方式:在集合內部使用Object[],而後當你使用數組元素時,添加一個對T的轉型。
javaprivate Object[] array; public T get(int index) { return (T) array[index];//Object轉型爲T } public T[] rep() { return (T[])array; //Object轉型爲T }
因此最終解決辦法是使用類型標記:
javaT[] array ; public Constructor(Class<T> type, int sz) { array = (T[]) Array.newInstance(type, sz); }
邊界 通配符 問題 自限定的類型 動態類型安全 異常 ....