1)基本概念:   泛型(Generic Type或Generics)是 对Java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看做是使用参数化类型时指定的类型的一个占位符,就像方法的形 式参数是运行时传递的占位符一样,泛型的体现主要是在集合框架里面可以看到,JCF里面应该是1.5里面使用泛型最多的地方。Java语言引入泛型是一个 较大的功能增强,不仅语言、类型系统和编译器有了大变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为了泛型化的 了,使用泛型的优点为:
类型安全  泛型的主要目标是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就 只存在于程序员的脑海中。Java程序中的一种流行技术是定义这样的集合,即它的元素或键是功能类型的,比如“_列表”。通过在变量声明中捕获这一附加的 类型信息,泛型允许编译器实施这些附加的约束,类型错误现在就可以在编译时被捕获了,而不是在运行时才来进行检测操作。
消除强制类型转换  泛型的一个附带的好处是,消除源代码中的许多强制类型转换,这使得代码更加可读,而且减少了出错的机会。比较两段代码:
1 2 3 List li = new  ArrayList();  li.add(new  Integer(3 ));  Integer i = (Integer)li.get(0 );  
 使用泛型:
1 2 3 List<Integer> li = new  ArrayList<Integer>();  li.add(new  Integer(3 ));  Integer i = li.get(0 );  
潜在的性能收获:  泛型为较大的优化带来可能。在泛型的初始实现中,编译器将类型转换插入到各种字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的JVM也带来了优化可能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  org.susan.java.enumeration;    class  GenClass <T >        T ob;         GenClass(T o){             this .ob = o;         }         T getOb ()  {             return  this .ob;         }         void  showType ()             System.out.println("Type of T is "  + ob.getClass().getName());         }     }     public  class  GenDemo          public  static  void  main (String args[])             GenClass<Integer> iObject = new  GenClass<Integer>(88 );             iObject.showType();         }     } 
这段代码的输出为:Type of T is java.lang.Integer
2)深入理解泛型: [1]数据类型转换:   在前边已经说过了,Java里面存在类的向下转型和向上转型,而且Java语言里面有时候比较容易因为类型的检查引发转型的问题,因为很多时候需要不断地向下转型,这种方式往往增加了JVM的一部分运行时的开销。实际上程序中每个向下转型针对ClassCastException都是潜在的危险, 应当尽量避免它们,但是在写程序的过程,这种转型往往没有办法避免,即使特别优良的设计也是会存在的。其实JDK 1.4到JDK 1.5的升级过程泛型是一个大的跨度,这种跨度使得编写程序更加规范,其实在前边讲解集合的时候已经使用了很多泛型的编程格式了,提供的很多代码Demo 都是泛型的。这里再提供一段简单的泛型使用代码:
  ——[$]使用泛型的 List——
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package  org.susan.java.generic;     import  java.util.ArrayList;      import  java.util.Iterator;      import  java.util.List;             public  class  ListGenericDemo           public  static  void  main (String args[])              List list = new  ArrayList();              List<String> genList = new  ArrayList<String>();              list.add("List 1" );              list.add("List 2" );              genList.add("Generic List 1" );              genList.add("Generic List 2" );              System.out.println("No Generic:" );              Iterator iterator = list.iterator();              while (iterator.hasNext()){                  System.out.print("["  + (String)iterator.next() + "]," );              }              System.out.println("\nGeneric:" );              Iterator<String> genIterator = genList.iterator();              while (genIterator.hasNext()){                  System.out.print("["  + genIterator.next() + "]," );              }          }      } 
上边这段代码的输出为:
1 2 3 4 No Generic: [List 1],[List 2], Generic: [Generic List 1],[Generic List 2], 
  这里使用了两种不同的方式【*: 在最原始的定义的List参数里面,不使用泛型的时候都是直接使用Object类型,在传入String的时候会进行向下转型,一般情况不会出现转型失败 的情况,但是使用了泛型过后,就上边的genList代码段里面,只能添加String对象,如果使用了其他类型的元素这里编译器就会直接报错,这种做法消除了JVM本身的类型转换。】
[2]基本类型限制   Tiger【Java 5.0的版本号】中 的类型变量的限制之一就是:必须使用引用类型进行实例化,基本类型不起作用,就是说不能使用:List list = new ArrayList();这种定义方式。也就是说在泛型使用的过程里面,如果要针对基本类型进行泛型使用,必须要进行包装,就是 Boxing操作,比如把int包装成为Integer。
  这里参考以下泛型的类型限制:JSR-14中:
 * 不应在静态成员中引用封闭类型参数中的T)针对T类型而言,T的上界就是Object。这一项技术的功能极其强大,我们可以使几乎所有泛型类型的精度增强,但 是与JVM兼容。 
1 2 3 4 5 6 7 8 9 package  org.susan.java.generic;    public  class  StaticListGenericDemo <T >         static  void  metho1 ()                     }         static  class  StaticClass                     }     } 
这里被注释掉的代码是不能通过JVM编译的,因为编译器完全禁止在静态方法和静态内部类中引用封闭类型参数,下边几种情况这里就不做解释了,T在整个过程里面是不应该作为外露类型来使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  org.susan.java.generic;     import  java.util.Hashtable;      interface  Registry          public  void  register (Object o)      }      class  C <T > implements  Registry          int  counter = 0 ;          Hashtable<Integer,T> values;          public  C ()              values = new  Hashtable<Integer,T>();          }          public  void  register (Object o)              values.put(new  Integer(counter), (T)o);              counter++;          }      } 
【*:这段代码编译没有任何问题,但是在(T)o地方会有一个警告,虽然这些警告本身没有什么,事实上,它们会使得诊断代码变得极为困难。在以前的代码中,我们认为如果对实例 C调用 register(“test”) ,会发出 ClassCastException 。但并非如此;计算将继续,就仿佛数据类型转换成功了一样,然后在进一步进行计算时发出错误,或者更糟:用遭破坏的数据完成计算,但不向外发出任何错误信号。同样,对“外露”类型参数的 instanceof 检查将在编译时产生 “unchecked”警告,而且检查将不会如期在运行时进行。】 
[3]泛型的构造函数: 在定义泛型的构造函数的时候,要解决这一个问题,需要一定的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  org.susan.java.generic;     class  GenGons          private  double  val;          <T extends Number> GenGons(T arg){              val = arg.doubleValue();          }          void  showVal ()              System.out.println("Val: "  + val);          }      }      public  class  GenGonsDemo           public  static  void  main (String args[])              GenGons genOne = new  GenGons(100 );              GenGons genTwo = new  GenGons(123.5F );              genOne.showVal();              genTwo.showVal();          }      } 
这段程序输出为:
[4]泛型中通配符的使用: 通配符——使 用一个?标识类型参数,是一种表示未知类型的约束方法。通配符并不包含在最初的泛型设计中,从形成JSR14到发布其最终版本之间的五年时间内完成了设计 添加到泛型中。通配符在泛型的使用中具有重要的意义,它们为一个泛型类所指定的类型集合提供了一个有用的类型范围。对泛型的ArrayList而言,对于 任意类型T,ArrayList>类型是ArrayList的超类型,但是这些超类型在执行类型推断方面是不起作用的。通配符类型List>、原始List和具体List都不相同。如果说变量X具有List<?>类型,标识存在一些T类型,其中x是List类型,x具有相同的结构,尽管我们不知道其元素的具体类型。这并不代表它具有任意内容,而是指我们并不了解内容的类型限制是什么 — 但我们知道存在 某种限制。另一方面,原始类型 List 是异构的,我们不能对其元素有任何类型限制,具体类型 List表示我们明确地知道它能包含任何对象(当然,泛型的类型系统没有 “列表内容” 的概念,但可以从 List 之类的集合类型轻松地理解泛型)。 通配符在类型系统中的作用部分来自其不会发生协变(covariant)这一特性。数组是协变的,因为 Integer 是 Number 的子类型,数组类型 Integer[] 是 Number[] 的子类型,因此在任何需要 Number[] 值的地方都可以提供一个 Integer[] 值。另一方面,泛型不是协变的, List不是 List的子类型,试图在要求 List的位置提供 List是一个类型错误。这不算很严重的问题,也不是所有人都认为的错误,但泛型和数组的不同行为的确引起了许多混乱。        
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package  org.susan.java.generic;     class  Status <T  extends  Number >         T[] nums;          Status(T[] o){              nums = o;          }          double  average ()              double  sum = 0.0 ;              for ( int  i = 0 ; i < nums.length; i++)                  sum += nums[i].doubleValue();              return  sum / nums.length;          }          boolean  sameAvg (Status<?> obj)              if ( average() == obj.average())                  return  true ;              return  false ;          }      }      public  class  WildcardDemo           public  static  void  main (String args[])              Integer inums[] = {1 ,2 ,3 ,4 ,5 };              Status<Integer> iobj = new  Status<Integer>(inums);              System.out.println("iob average is " + iobj.average());              Double dnums[] = {1.1 ,2.2 ,3.3 ,4.4 ,5.5 };              Status<Double> dobj = new  Status<Double>(dnums);              System.out.println("dob average is " + dobj.average());              Float fnums[] = {1.1F ,2.2F ,3.3F ,4.4F ,5.5F };              Status<Float> fobj = new  Status<Float>(fnums);              System.out.println("fob average is " + fobj.average());          }      } 
这段程序的输出为:
1 2 3 iob average is 3.0  dob average is 3.3  fob average is 3.300000023841858  
——[$]返回泛型值的方法——
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  org.susan.java.generic;   import  java.io.Serializable;    class  Base    class  SubClass  extends  Base  implements  Serializable    class  SubClassTwo  extends  Base  implements  Serializable    public  class  TypeInference         public  static  <T extends Base> T Method (T t1,T t2)  {            return  null ;        }        public  static  void  main (String args[])            Base base = Method(new  SubClass(), new  SubClassTwo());            Serializable run = Method(new  SubClass(), new  SubClassTwo());        }    } 
注意上边返回值的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  org.susan.java.generic;     import  java.util.ArrayList;      import  java.util.List;             public  class  QuestionDemo           private  static  void  testMethod (List<? extends Number> list)          public  static  void  main (String args[])              List<Object> oList = new  ArrayList<Object>();              List<Integer> iList = new  ArrayList<Integer>();              List<Number> nList = new  ArrayList<Number>();                           testMethod(iList);              testMethod(nList);          }      } 
从上边的的代码可以知道,?一般和extends以及super关键字进行使用,其含义在于传入泛型的类型定义为extends后边的类型的子类,所以上边的注释掉的代码是没有办法通过编译的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package  org.susan.java.generic;   interface  MinMan <T  extends  Comparable <T >>       T min ()  ;        T max ()  ;    }    class  MyDemo <T  extends  Comparable <T >> implements  MinMan <T >       T[] tValues;        MyDemo(T[] o){ tValues = o;}        public  T min ()            T vT = tValues[0 ];            for ( int  i = 1 ; i < tValues.length; i++ )                if (tValues[i].compareTo(vT) < 0 )                    vT = tValues[i];            return  vT;        }        public  T max ()            T vT = tValues[0 ];            for ( int  i = 1 ; i < tValues.length; i++ )                if (tValues[i].compareTo(vT) >  0 )                    vT = tValues[i];            return  vT;        }    }    public  class  GenericInterface         public  static  void  main (String args[])            Integer inums[] = {3 ,6 ,13 ,11 ,45 ,22 ,33 ,21 };            MyDemo<Integer> iob = new  MyDemo<Integer>(inums);            System.out.println("iob Max:"  + iob.max());            System.out.println("iob Min:"  + iob.min());        }    } 
该输出为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package  org.susan.java.generic;        class  MyGenDemo <T ,V >       T ob1;        V ob2;        void  set (T o)            this .ob1 = o;        }        void  set (V o)            this .ob2 = o;        }    }    class  GenDemo <T >       T ob;        GenDemo(){            this .ob = new  T();        }    }    class  Wrong <T >       static  T ob;        static  T getOb ()            return  ob;        }    } 
分析上边的代码段就可以发现很多问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package  org.susan.java.generic;     class  GenType <T >         T ob;          GenType(T ob){              this .ob = ob;          }          T getOb ()  {              return  this .ob;          }      }      class  GenStr <T  extends  Number >         T str;          GenStr(T o){              this .str = o;          }          T getStr ()  {              return  this .str;          }      }      public  class  GenTypeDemo           public  static  void  main (String args[])              GenType<Integer> iObGenType = new  GenType<Integer>(99 );              GenStr<Float> fOb = new  GenStr<Float>(102.2F );              System.out.println(iObGenType.getClass().getName());              System.out.println(fOb.getClass().getName());          }      } 
根据输出结果可以知道该类型就为我们定义的类型:
3)泛型“类型捕获” 协变概念【extends 和super】 讲了这么多泛型的内容,相信读者对泛型有一点点了解了,接下来针对泛型里面比较费解的地方进行比较通俗的讲解,泛型的类型捕获是从编译器的级别来说的,当我们定义了泛型的时候,如果使用了? extends T这 种格式,编译器遇到一个这样带有通配符的变量的时候,它如何来进行识别操作呢,它会觉得遇到T了过后,一定会有T定义的变量,而对这些T而言一定有一个 Class类型。但是它不知道T代表什么,但是JVM会为T定制一个占位符来代替T的类型。占位符被称为特殊通配符的捕获。这种情况 下,编译器会为通配符提供一个名字,每个变量声明中出现的一个通配符都会活得JVM的一个捕获,,因此在泛型声明中如果用了public void method(Pointer,?> pointer)的话,JVM就会获取两个通配符名称,因为这个时候?也好,T也好,类型是未知的,任意未知的类型的参数在使用的时候相互之间是没有任何关系的。格式的,然后是外露类型T,这里T就代表了外露类型,这里需要区分这种情况下Type和Type不属于同一个类型。这里需要了解的是泛型的“协变”。也会是 List的子类,但是这种做法在泛型里面是错误的。这种做法在传入的时候会被编译器定义为类型错误。看一段程序:     
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package  org.susan.java.generic;     import  java.util.ArrayList;      import  java.util.List;             public  class  ChangeGenerice           private  static  void  methodOne (List<Number> number)              System.out.println("One:"  + number);          }          private  static  void  methodTwo (List<Integer> integer)              System.out.println("Two:"  + integer);          }          private  static  void  methodThree (List<? extends Number> number)              System.out.println("Three:"  + number);          }          private  static  void  methodFour (List<? super  Number> integer)              System.out.println("Four:"  + integer);          }          public  static  void  main (String args[])              List<Number> nList = new  ArrayList<Number>();              List<Integer> iList = new  ArrayList<Integer>();              List<Object> oList = new  ArrayList<Object>();              methodOne(nList);                                        methodThree(nList);              methodFour(nList);                                        methodTwo(iList);              methodThree(iList);                                                                                            methodFour(oList);          }      } 
如果需要在1.5的JDK环境里面进行1.4的写法,如果不去掉类型检测可能会报警告: