1. 程式人生 > >Java中的泛型--generic

Java中的泛型--generic

sys 基本類型 wap ram 其它 自定義 lis 綜合案例 .get

  學習一下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