java 泛型

 轉載:http://www.blogjava.net/fancydeepin

泛型的好處:

 
    泛型的主要好處就是讓編譯器保留參數的類型信息,執行類型檢查,執行類型轉換(casting)操作,編譯器保證了這些類型轉換(casting)的絕對無誤。
 
  1. /******* 不使用泛型類型 *******/ 
  2.        List list1 = new ArrayList(); 
  3.        list1.add(8080);//編譯器不檢查值 
  4.        String str1 = (String)list1.get(0); //需手動強制轉換,如轉換類型與原數據類型不一致將拋出ClassCastException異常 
  5.         
  6.        /******* 使用泛型類型 *******/ 
  7.        List<String> list2 = new ArrayList<String>(); 
  8.        list2.add("value");//[類型安全的寫入數據] 編譯器檢查該值,該值必須是String類型才能通過編譯 
  9.        String str2 = list2.get(0); //[類型安全的讀取數據] 不需要手動轉換 
泛型的類型擦除:
 
    Java 中的泛型只存在於編譯期,在將 Java 源文件編譯完成 Java 字節代碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數,會被編譯器在編譯的時候去掉。
 
    這個過程就稱爲類型擦除(type erasure)。
 
  1. List<String>    list1 = new ArrayList<String>(); 
  2.         List<Integer> list2 = new ArrayList<Integer>(); 
  3.          
  4.         System.out.println(list1.getClass() == list2.getClass()); // 輸出結果: true 
  5.         System.out.println(list1.getClass().getName()); // 輸出結果: java.util.ArrayList 
  6.         System.out.println(list2.getClass().getName()); // 輸出結果: java.util.ArrayList 
在以上代碼中定義的 List<String> 和 List<Integer> 等類型,在編譯之後都會變成 List,而由泛型附加的類型信息對 JVM 來說是不可見的,所以第一條打印語句輸出 true,
 
第二、第三條打印語句都輸出 java.util.ArrayList,這都說明 List<String> 和 List<Integer> 的對象使用的都是同一份字節碼,運行期間並不存在泛型。
 
來看一個簡單的例子:
 
 
 
  1. package test; 
  2.  
  3. import java.util.List; 
  4. /** 
  5.  * ----------------------------------------- 
  6.  * @描述  類型擦除 
  7.  * @作者  fancy 
  8.  * @郵箱  [email protected] 
  9.  * @日期  2012-8-25 <p> 
  10.  * ----------------------------------------- 
  11.  */ 
  12. public class GenericsApp { 
  13.  
  14.      
  15.     public void method(List<String> list){ 
  16.          
  17.     } 
  18.      
  19.     /* 
  20.      * 編譯出錯,這兩個方法不屬於重載,由於類型的擦除,使得這兩個方法的參數列表的參數均爲List類型, 
  21.      * 這就相當於同一個方法被聲明瞭兩次,編譯自然無法通過了 
  22.      *  
  23.     public void method(List<Integer> list){ 
  24.          
  25.     } 
  26.     */ 
  27.      
 
以此類爲例,在 cmd 中 編譯 GenericsApp.java 得到字節碼,然後再反編譯這份字節碼:
 
 
 
從圖中可以看出,經反編譯後的源碼中 method 方法的參數變成了 List 類型,說明泛型的類型被擦除了,字節碼文件中不存在泛型,也就是說,運行期間泛型並不存在,它在
 
編譯完成之後就已經被擦除了。
 
 
泛型類型的子類型:
 
    泛型類型跟其是否是泛型類型的子類型沒有任何關係。
 
  1. List<Object> list1; 
  2.        List<String> list2; 
  3.         
  4.        list1 = list2; // 編譯出錯 
  5.        list2 = list1; // 編譯出錯 
       
在 Java 中,Object 類是所有類的超類,自然而然的 Object 類是 String 類的超類,按理,將一個 String 類型的對象賦值給一個 Object 類型的對象是可行的,
 
但是泛型中並不存在這樣的邏輯,泛型類型跟其是否子類型沒有任何關係。
 
 
泛型中的通配符(?):
 
    由於泛型類型與其子類型存在不相關性,那麼在不能確定泛型類型的時候,可以使用通配符(?),通配符(?)能匹配任意類型。
 
  1. List<?> list; 
  2.        List<Object> list1 = null
  3.        List<String>  list2 = null
  4.         
  5.        list = list1; 
  6.        list = list2; 
       
限定通配符的上界:
 
  1. ArrayList<? extends Number> collection = null
  2.         
  3.        collection = new ArrayList<Number>(); 
  4.        collection = new ArrayList<Short>(); 
  5.        collection = new ArrayList<Integer>(); 
  6.        collection = new ArrayList<Long>(); 
  7.        collection = new ArrayList<Float>(); 
  8.        collection = new ArrayList<Double>(); 
  9.         
 
 ? extends XX,XX 類是用來限定通配符的上界,XX 類是能匹配的最頂層的類,它只能匹配 XX 類以及 XX 類的子類。在以上代碼中,Number 類的實現類有:
 
AtomicInteger、AtomicLong、 BigDecimal、 BigInteger、 Byte、 Double、 Float、 Integer、 Long、 Short ,因此以上代碼均無錯誤。
 
 
限定通配符的下界:
 
 
        
  1. ArrayList<? super Integer> collection = null
  2.          
  3.         collection = new ArrayList<Object>(); 
  4.         collection = new ArrayList<Number>(); 
  5.         collection = new ArrayList<Integer>(); 
  6.          
 
 ? super XX,XX 類是用來限定通配符的下界,XX 類是能匹配的最底層的類,它只能匹配 XX 類以及 XX 類的超類,在以上代碼中,Integer 類的超類有:
 
Number、Object,因此以上代碼均能通過編譯無誤。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章