Java中的泛型--generic
學習一下Java中的泛型,還是張孝祥老師很好的講解。。。jdk 1.5中新增的特性
一、泛型初探
泛型在Java中挺常用的,尤其是項目中也是比較常用的,但是用起來感覺好用,並沒有深入的去理解一下,泛型是提供給javac編譯器使用的,可以限定集合中的輸入類型,讓編譯器擋住源程序中的非法輸入,編譯器編譯帶類型說明的集合時會去掉“類型”信息,使得程序運行不受影響,對於參數化的泛型類型,getClass() 方法的返回值和原始類型完全一樣。由於編譯生成的字節碼會去掉泛型的類型信息,只要能跳過編譯器,就可以往某個泛型集合中加入其它類型的數據,例如,用反射得到集合,在調用其add()方法即可。
1 ArrayList<String> collection1 = new ArrayList<String>(); 2 collection1.add("123"); 3 4 ArrayList<Integer> collection2 = new ArrayList<Integer>(); 5 collection2.add(11); 6 7 // 結果為 true 實際編譯完成之後 實際上是相同的基本類型 8 System.out.println(collection1.getClass() == collection2.getClass());9 // 利用反射可以跳過編譯器 10 collection2.getClass().getMethod("add", Object.class).invoke(collection2, "abc"); 11 System.out.println(collection2.get(1));
ArrayList<E> 這種是泛型類型;
E稱為泛型變量或者是泛型參數;
ArrayList<Integer>稱為參數化的類型;
Integer稱為類型參數的實例或者是實際類型參數;
ArrayList為原始類型
二、泛型中的 ? 通配符
總結:使用?通配符可以引用各種參數化的類型,?通配符定義的變量只是用作引用,可以調用與參數化無關的方法,不能調用與參數化有關的方法
通配符的擴展:
1) 限定通配符的上邊界
正確:Vector<? extends Number> x = new Vector<Integer>();
這種是後面new出來的可以是extends 的子類,例如:Integer 是Number 的子類,是繼承關系
錯誤:Vector<? extends Number> x = new Vector<String>();
2)限定通配符的下邊界
正確:Vector<? super Integer> x = new Vector<Number>();
這種是後面new出來的是前面的父類,正好和上面的相反,例如:Number 是Integer的父類
錯誤:Vector<? super Integer> x = new Vector<Byte>();
三、泛型集合類的綜合案例
1 // 簡單的map中元素的叠代 2 Map<String,Integer> maps = new HashMap<String,Integer>(); 3 maps.put("A", 27); 4 maps.put("B", 28); 5 6 Set<Map.Entry<String, Integer>> entrySet = maps.entrySet(); 7 for(Map.Entry<String, Integer> entry : entrySet){ 8 System.out.println(entry.getKey() + ":" + entry.getValue()); 9 }
四、自定義泛型方法和應用
1、只有引用類型才能作為泛型方法的實際參數,swap(new int[3]{1,2,3},1,2)語句會報編譯錯誤
2、除了在應用泛型時可以使用extends限定符,在定義泛型的時候也可以使用extends限定符
3、普通方法、構造方法和靜態方法中都可以使用泛型
4、在泛型中可以同時有多個類型參數,在定義他們的尖括號中用逗號分,例如:
public static <K,V> v getValue(K key){return map.getKey()};
1 // 交換數組中任意下標中兩個元素的位置 2 private static <T> void swap(T[] a, int i, int j){ 3 T tmp = a[i]; 4 a[i] = a[j]; 5 a[j] = tmp; 6 }
5、當一個變量被聲明為泛型時,只能被實例變量和方法調用(還有內嵌類型),而不能被靜態變量和方法調用,因為靜態成員是被所有的參數化的類所共享的,所以靜態成員不應該有類級別的類型參數
1 // 例如baseDao中經常那樣定義成泛型類,註意:靜態成員沒有類級別的類型參數 2 public class GenericDao <T>{ 3 4 public void add(T t){ 5 6 } 7 8 public T findById(int id){ 9 return null; 10 } 11 12 public void delete(T obj){ 13 14 } 15 16 public void delete(int id){ 17 18 } 19 20 public T update(T obj){ 21 return null; 22 } 23 24 public Set<T> findByConditions(String where){ 25 return null; 26 } 27 28 }
五、通過反射獲取泛型的實際類型參數
這個問題從來沒有思考過,用過框架,但是並沒有仔細思考過,為什麽,底層是怎麽楊實現的呢,今天看了張老師的視頻,感覺自己就是在工作上掙錢,並沒有投入太多的熱情在學習中,在工作中,這也許就是為什麽會和別人的差距越來越大,這是很值得深思的問題啊,看一下具體的怎麽實現的,記住這個,以後再用框架的時候,可以多思考一下
1 // 為什麽用Vector.class而不用Vector<Date>.class 後面的本身就是錯誤的,在編譯之後會將泛型擦除掉,其實本質還是Vector 2 Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class); 3 Type[] types = applyMethod.getGenericParameterTypes(); 4 ParameterizedType pType = (ParameterizedType) types[0]; 5 System.out.println(pType.getRawType()); 6 System.out.println(pType.getActualTypeArguments()[0]); 7 8 // 將需要獲取泛型類型的變量交給一個方法,當做參數來獲取其中參數的實際類型 9 public static void applyVector(Vector<Date> v1){ 10 11 }
這裏具體是在哪些框架中應用到了,現在還沒有太清楚的,希望以後再看框架源碼的時候,可以重新得到啟發。
Java中的泛型--generic