转载: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 list2 = new ArrayList(); 
  8.        list2.add("value");//[类型安全的写入数据] 编译器检查该值,该值必须是String类型才能通过编译 
  9.        String str2 = list2.get(0); //[类型安全的读取数据] 不需要手动转换 
泛型的类型擦除:
 
    Java 中的泛型只存在于编译期,在将 Java 源文件编译完成 Java 字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。
 
    这个过程就称为类型擦除(type erasure)。
 
   
   
   
   
  1. List    list1 = new ArrayList(); 
  2.         List list2 = new ArrayList(); 
  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 和 List 等类型,在编译之后都会变成 List,而由泛型附加的类型信息对 JVM 来说是不可见的,所以第一条打印语句输出 true,
 
第二、第三条打印语句都输出 java.util.ArrayList,这都说明 List 和 List 的对象使用的都是同一份字节码,运行期间并不存在泛型。
 
来看一个简单的例子:
 
 
 
   
   
   
   
  1. package test; 
  2.  
  3. import java.util.List; 
  4. /** 
  5.  * ----------------------------------------- 
  6.  * @描述  类型擦除 
  7.  * @作者  fancy 
  8.  * @邮箱  [email protected] 
  9.  * @日期  2012-8-25 

     

  10.  * ----------------------------------------- 
  11.  */ 
  12. public class GenericsApp { 
  13.  
  14.      
  15.     public void method(List list){ 
  16.          
  17.     } 
  18.      
  19.     /* 
  20.      * 编译出错,这两个方法不属于重载,由于类型的擦除,使得这两个方法的参数列表的参数均为List类型, 
  21.      * 这就相当于同一个方法被声明了两次,编译自然无法通过了 
  22.      *  
  23.     public void method(List list){ 
  24.          
  25.     } 
  26.     */ 
  27.      
 
以此类为例,在 cmd 中 编译 GenericsApp.java 得到字节码,然后再反编译这份字节码:
 
 
 
从图中可以看出,经反编译后的源码中 method 方法的参数变成了 List 类型,说明泛型的类型被擦除了,字节码文件中不存在泛型,也就是说,运行期间泛型并不存在,它在
 
编译完成之后就已经被擦除了。
 
 
泛型类型的子类型:
 
    泛型类型跟其是否是泛型类型的子类型没有任何关系。
 
   
   
   
   
  1. List list1; 
  2.        List list2; 
  3.         
  4.        list1 = list2; // 编译出错 
  5.        list2 = list1; // 编译出错 
  6.        
    在 Java 中,Object 类是所有类的超类,自然而然的 Object 类是 String 类的超类,按理,将一个 String 类型的对象赋值给一个 Object 类型的对象是可行的,
     
    但是泛型中并不存在这样的逻辑,泛型类型跟其是否子类型没有任何关系。
     
     
    泛型中的通配符(?):
     
        由于泛型类型与其子类型存在不相关性,那么在不能确定泛型类型的时候,可以使用通配符(?),通配符(?)能匹配任意类型。
     
       
       
       
       
    1. List list; 
    2.        List list1 = null
    3.        List  list2 = null
    4.         
    5.        list = list1; 
    6.        list = list2; 
    7.        
      限定通配符的上界:
       
         
         
         
         
      1. ArrayListextends Number> collection = null
      2.         
      3.        collection = new ArrayList(); 
      4.        collection = new ArrayList(); 
      5.        collection = new ArrayList(); 
      6.        collection = new ArrayList(); 
      7.        collection = new ArrayList(); 
      8.        collection = new ArrayList(); 
      9.         
       
       ? extends XX,XX 类是用来限定通配符的上界,XX 类是能匹配的最顶层的类,它只能匹配 XX 类以及 XX 类的子类。在以上代码中,Number 类的实现类有:
       
      AtomicInteger、AtomicLong、 BigDecimal、 BigInteger、 Byte、 Double、 Float、 Integer、 Long、 Short ,因此以上代码均无错误。
       
       
      限定通配符的下界:
       
       
              
         
         
         
         
      1. ArrayListsuper Integer> collection = null
      2.          
      3.         collection = new ArrayList(); 
      4.         collection = new ArrayList(); 
      5.         collection = new ArrayList(); 
      6.          
      7.  
         ? super XX,XX 类是用来限定通配符的下界,XX 类是能匹配的最底层的类,它只能匹配 XX 类以及 XX 类的超类,在以上代码中,Integer 类的超类有:
         
        Number、Object,因此以上代码均能通过编译无误。

        你可能感兴趣的:(java,泛型,JAVA)