参考文章:http://www.infoq.com/cn/articles/cf-java-generics

1、Java泛型是Java5以后才出现的特性,主要是为了代码重用的同时在编译器来避免类型转换问题。泛型的存在的意义在于类型替换,和禁止一些可能出现类型转换问题的编码,在编译期就报错

2、Java源代码首先通过编译得到class字节码文件,然后在jvm中运行。java class文件中是不存在类型信息的,也就是说开始定义的泛型都会在编译后消失。这就是类型檫除,Java中的泛型基本上都是在编译器这个层面上实现的。例如

List<String>和List<Integer>等类型在编译之后都变成List。因此有以下几种特性:

(1)只存在List.class,而不存在List<String>.class,List<Integer>.class

(2)静态变量是由类的所有实例共享的,因此不能定义泛型的静态变量

  1. public class MyClass<T>{ 
  2.    private static T s;//编译错误 

(3)异常类是在运行时抛出,通过catch捕获,但是运行时类型信息被抹去,所以对于MyException<String>和MyException<Integer>对于catch来说无法分辨

3、编译期间,对于泛型T来说,先用object进行替换,如果利用extends定义了上界,那么就利用上界类进行替换。

4、通配符?和上下界extends、super

(1)通配符?表示类型未知,因此可以传入任意类型。从语法层面上规定了通配符指定的对象不能实例化,因为类型未知。例如new ArrayList<?>()是错误的。下面例子中的alist.add(1)也是禁止的,因为List类型未知。试图对一个带通配符的泛型类进行操作都会出现编译错误。它和List<Object>的区别在于,即使是Object也是类型已知可以进行操作和实例化,所以下面代码中blist.add(1)是不会报错的。如果参数是List<Object>,传入List<String>,虽然理解上是可以的,但是编译器为了避免出现blist.add(1)这种在String列表中加入Integer的行为导致的ClassCastException,所以禁止这样做。

(2)定义泛型后,就给原来的继承体系增加了一个维度。例如Collection<? extends Number> ,List<Integer>,Set<Integer>和List<Double>,Set<Double>都是其子类,都可以作为匹配参数传入

下面的代码

  1. public class GenericTest<T extends Number> { 
  2.     public void get(List<?> alist) { 
  3.         alist.get(0); 
  4.   alist.add(1);//?通配符,表示类型未定,编译器禁止add 
  5.     } 
  6.  
  7.     public void getO(List<Object> blist) { 
  8.   blist.add(1);//在该函数内部,list加入一个整型是没错的 
  9.     } 
  10.  
  11.     public void test() { 
  12.         get(new ArrayList<String>());//正确 
  13.         get(new ArrayList<Integer>());//正确 
  14.         getO(new ArrayList<String>());//编译错误,因为可能会出现潜在的类型转换问题 
  15.     } 

(3)?extends XX限定了?匹配的上界,只有XX及其子类可以通过匹配。其主要应用场景是可以get得到XX的引用,来调用XX指定的方法,但是不能直接add,因为传入的参数确定的类型是其子类,add父类是不行的

(4)?super XX限定了?匹配的下界,只有XX及其父类可以通过匹配。其主要应用可以add加入XX的实例,因为XX是下界,传入的只能是XX及其父类,向上转型是可以的。但是不能get到XX的引用

  1. public class GenericTest<T extends Number> { 
  2.     
  3.     public void get1(List<? extends B> alist) { 
  4.  
  5.     } 
  6.     public void get2(List<? super B> alist) { 
  7.  
  8.     } 
  9.     public void test() { 
  10.         get1(new ArrayList<A>());//编译错误,B或者其子类 
  11.         get1(new ArrayList<B>()); 
  12.         get1(new ArrayList<C>()); 
  13.         get2(new ArrayList<A>()); 
  14.         get2(new ArrayList<B>()); 
  15.         get2(new ArrayList<C>());//编译错误,B或者其父类 
  16.     } 
  17.   
  18.  public void upperBound(List<? extends Date> list, Date date)   
  19.  {   
  20.       Date now = list.get(0);   
  21.       System.out.println("now==>" + now);   
  22.      //list.add(date); //这句话无法编译   
  23.      list.add(null);//这句可以编译,因为null没有类型信息   
  24.  } 
  25.  //可能的调用导致上界约束的add方法错误 
  26.  public void testUpperBound()   
  27.  {   
  28.       List<Timestamp> list = new ArrayList<Timestamp>();   
  29.      Date date = new Date();   
  30.      upperBound(list,date);   
  31.  } 
  32.  public void lowerBound(List<? super Timestamp> list)   
  33.  {   
  34.      Timestamp now = new Timestamp(System.currentTimeMillis());   
  35.      list.add(now);   
  36.       //Timestamp time = list.get(0); //不能编译   
  37.  }   
  38.  //可能的调用导致下界约束get方法错误 
  39.  public void testLowerBound()   
  40.  {   
  41.      List<Date> list = new ArrayList<Date>();   
  42.      list.add(new Date());   
  43.      lowerBound(list);   
  44.  }  
  45.  
  46. class A { 
  47.  
  48. class B extends A { 
  49.  
  50. class C extends B { 

5、泛型方法:是否拥有泛型方法与是否在泛型类中无关,只需在返回值前加上<T>就行

  1. public class GenericTest { 
  2.     public <T> List<T> get(T t) { 
  3.         return new ArrayList<T>(); 
  4.     } 
  5.  
  6.     public void test() { 
  7.         String s = ""
  8.         List<String> list = get(s); 
  9.         list.add("tt"); 
  10.         list.add("ee"); 
  11.         for(String a:list){ 
  12.             System.out.println(a); 
  13.         } 
  14.     } 
  15.  
  16.     public static void main(String[] args) { 
  17.         GenericTest test=new GenericTest(); 
  18.         test.test(); 
  19.     } 

第23条:请不要在新代码中使用原生态类型

如果使用原生态类型,就失掉了泛型在安全性和表述性方面的所有优势