java 泛型学习笔记

java泛型从JDK1.5开始出来的,虽然自己平时也有用到,但是一直没有全面的学习,今天在看myibatis3.0.1源码时,看到多处用到泛型设计,所以自己把泛型学习了下。

 

什么是泛型?

    在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点就是被Object引用对象被“上塑”造型,对象的具体类型信息被丢失,这样当我们要使用该类型时要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

  泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

 

泛型使用的规则和限制

  1. 泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
  2. 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
  3. 泛型的类型参数可以有多个。
  4. 泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
  5. 泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");

泛型的基本使用

    eg1:使用了泛型

Java代码  收藏代码
  1. package com.kyle.Generics.ch01;  
  2.   
  3.   
  4. /** 
  5.  * 定义泛型类型 
  6.  * @author kyle 
  7.  * 
  8.  * @param <T> 
  9.  */  
  10. public class SimpleDemo1<T> {  
  11.     private T ob;//定义泛型成员变量  
  12.       
  13.     public T getOb() {  
  14.         return ob;  
  15.     }  
  16.   
  17.     public void setOb(T ob) {  
  18.         this.ob = ob;  
  19.     }  
  20.   
  21.     public SimpleDemo1(T ob){  
  22.           
  23.         this.ob=ob;  
  24.     }  
  25.       
  26.     public  void showType(){  
  27.           
  28.         System.out.println("T的实际类型是:"+ob.getClass().getName());  
  29.     }  
  30.       
  31.     public static void main(String args[]){  
  32.         //定义泛型SimpleDemo的一 个Integer版本  
  33.         SimpleDemo1<Integer> intObj=new SimpleDemo1<Integer>(88);  
  34.         //不需要转换可以得到ob的具体类型  
  35.         Integer  intValue=intObj.getOb();  
  36.         intObj.showType();  
  37.           
  38.           
  39.         //定义泛型SimpleDemo的一个String版本  
  40.           
  41.         SimpleDemo1<String> strObj=new SimpleDemo1<String>("Hello world");  
  42.         //不需要转换可以得到ob的具体类型  
  43.         String strValue=strObj.getOb();  
  44.         strObj.showType();  
  45.         String str=strObj.getOb();  
  46.         System.out.println("ob is vlaue :"+str);  
  47.           
  48.           
  49.     }  
  50.       
  51.   
  52. }  

 

eg2:没有使用泛型实现

Java代码  收藏代码
  1. package com.kyle.Generics.ch01;  
  2.   
  3. /** 
  4.  * 没有使用泛型 
  5.  * @author kyle 
  6.  * 
  7.  */  
  8. public class SimpleDemo2{  
  9.       
  10.     private Object ob; //定义一个通用类型成员   
  11.       
  12.     public SimpleDemo2(Object ob) {  
  13.         this.ob = ob;   
  14.     }   
  15.       
  16.     public Object getOb() {  
  17.         return ob;  
  18.     }  
  19.   
  20.     public void setOb(Object ob) {  
  21.         this.ob = ob;  
  22.     }  
  23.   
  24.       
  25.       
  26.     public  void showType(){  
  27.           
  28.         System.out.println("Object的实际类型是:"+ob.getClass().getName());  
  29.     }  
  30.       
  31.     public  static void main(String args[]){  
  32.         SimpleDemo2  intObj=new  SimpleDemo2(new Integer(88));  
  33.                int intValue=(Integer)intObj; //强制转换成Integer  
  34.         intObj.showType();  
  35.   
  36.   
  37.         SimpleDemo2  strObj=new SimpleDemo2(new String("Hello Gen2"));  
  38.                String  strValue=(String)strObj;//强制转换成String   
  39.         strObj.showType();  
  40.           
  41.     }  
  42.   
  43. }  

 

  通过上面两个DEMO的比较,我们可以很直接的看到泛型给我们带来的易用性。在这里DEMO1中我们可以简单的假想为T就是我们构造对象时动态传入的字符串,例如

SimpleDemo1<Integer> intObj=new SimpleDemo1<Integer>(88)传入的是Integer,那么private T ob 就变成private Integer ob,SimpleDemo1<String> strObj=new SimpleDemo1<String>("Hello world")传入的String,那么private T ob就变成private String ob。T就相当于是一个类型变量,编译器在编译时把该变量替换成我们传入的类型。

 

 

泛型的高级应用

 1.限制泛型的可用类型

     class GenericsFoo<T extends Collection>,这样的泛型T只能是Collection接口的实现类或者子接口,传入非Collection接口则会编译报错

  注意:<T extends Collection>这里的限定使用关键字extends ,实际T的类型Collection可以是实现Collection接口的类也可以是继承了Collection接口,  extends只是起一个限定作用,而非继承的意义。

 

 eg: 

Java代码  收藏代码
  1. package com.kyle.Generics.ch03;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.LinkedList;  
  6.   
  7. public class CollectionGenFoo <T extends Collection>{  
  8.       
  9.     private T x;  
  10.       
  11.    public CollectionGenFoo( T x){  
  12.           
  13.         this.x=x;  
  14.           
  15.     }  
  16.       
  17.     public T getX() {  
  18.         return x;  
  19.     }  
  20.   
  21.     public void setX(T x) {  
  22.         this.x = x;  
  23.     }  
  24.       
  25.     public static void main(String args[]){  
  26.           
  27.         <span style="color: #58a340;">/**1 
  28.           * 定义CollectionGenFoo的泛型为ArrayList 
  29.           * 即定义listFoo这个引用只接受泛型为 
  30.           * ArrayList类型的实例 
  31.           * 我们构造函数传入new ArrayList()传入的正是ArrayList类型 
  32.           */  
  33. </span>  
  34.   
  35.   
  36.           CollectionGenFoo<ArrayList> listFoo = null;  
  37.            listFoo=new CollectionGenFoo<ArrayList>(new ArrayList());  
  38.                                  listFoo.getX();//该方法返回的对象为ArryList类型  
  39.        <span style="color: #58a340;"/**2 
  40.            * 定义CollectionGenFoo的泛型为Collection 
  41.            * 即定义listFoo这个引用只接受泛型为 
  42.            * Collection类型的实例 
  43.            *  我们构造函数传入new ArrayList()是Collection接口的实现类 
  44.            *  也是Collection类型的 
  45.           */  
  46. </span>  
  47.   
  48.   
  49.           CollectionGenFoo<Collection> listFoo2 = null;  
  50.           listFoo2=new CollectionGenFoo<Collection>(new ArrayList());  
  51.                                   listFoo2.getX();//该方法返回的对象为Collection类型       
  52.         <span style="color: #58a340;">  /**3 
  53.            * 下面的报错 
  54.            *CollectionGenFoo<String>中的类型必须是 Collection类型的 
  55.                */  
  56. </span>  
  57.   
  58.   
  59.           //CollectionGenFoo<String> listFoo3=null;  
  60.      
  61.      
  62.          <span style="color: #58a340;">/**4 
  63.          * 下面的报错,因为声明的引用已经定义参数必须为Collection类型的 
  64.          * 那么new CollectionGenFoo<ArrayList>传入的类型必须与引用一致 
  65.          * 即T这个类型变量不能同时为两个值 
  66.          */  
  67. </span>  
  68.   
  69.   
  70.               //CollectionGenFoo<Collection> listFoo4 = null;  
  71.           //listFoo4=new CollectionGenFoo<ArrayList>(new ArrayList());  
  72.     }  
  73.   
  74.       
  75. }  

 

 

   通过这个例子,我们应该仔细对比1,2,3,4这三种声明方式,体会泛型的含义:

   1.从1,2,3可以看出使用“有界泛型”<T extends SuperClass>这种声明方式 时,类型参数T必须是SuperClass的子类或者SuperClass类型。如果不是则会在编译时报:

       Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends Collection> of the type            CollectionGenFoo<T> 这个错误。

   2.从4可以看出<T extends SuperClass>中的T虽然可以是任意SuperClass的任意类型,但是一旦引用指定具体类型以后,实例的泛型类型必须和引用是一致,在这里 并不存在什么父子关系, 即类型T不能前后赋两个不同值。

 

   2.通配符泛型

     在上面的例子中对于当我们声明某一种特定泛型类型的引用时,那么对应的实例的泛型类型就必须和引用的泛型类型一样,这样当我们有多个泛型类型子类实例时,我们就必须声明多个不同的引用,也就是我们的引用被具体化了,换句话说,我们的泛型被具体化了,所以才导致我们的引用也被具体化了。那么如何让一个含有泛型的引用

也可以接受任意的实例类型?

 

  eg: 继续上面的DEMO,在main方法中加入如下声明方式

 

Java代码  收藏代码
  1.               <span style="color: #008000;">/**5 
  2.  * 使用通配符CollectionGenFoo<? extends Collection>  
  3.  * listFoo5这个引用接受所有Collection类型 的实例 
  4.  *  
  5.  */  
  6. span>  
  7. CollectionGenFoo<? extends Collection> listFoo5 = null;  
  8. listFoo5=new CollectionGenFoo<ArrayList>(new ArrayList());  
  9. listFoo5=new CollectionGenFoo<LinkedList>(new LinkedList());  
  10. listFoo5.getX();//该方法返回值的类型为Collection类型  
  11.   
  12.   
  13. /** 
  14.  * CollectionGenFoo<?>方式声明引用时 
  15.  * listFoo5这个引用接受所有Collection类型的实例 
  16.  *  
  17.  */  
  18. CollectionGenFoo<?> listFoo6 = null;  
  19. listFoo6=new CollectionGenFoo<ArrayList>(new ArrayList());  
  20. listFoo6=new CollectionGenFoo<LinkedList>(new LinkedList());  
  21. listFoo6.getX();//该方法返回值的类型为Object类型  
  22.      
  23. span style="color: #008000;">   /* 
  24.  * 下面的报错: 
  25.  * 虽然通配符?可以是任意类型,但是也是有限制的 
  26.  * 必须是Collection的子类 
  27.  */  
  28.               /*报错: 
  29.                 *Bound mismatch: The type String is not a valid substitute for the bounded parameter 
  30.                 *<T extends Collection> of the type CollectionGenFoo<T> 
  31.                 */</span>  
  32.   
  33.         //listFoo6=new CollectionGenFoo<String>(new String("test"));  
  34.                
 

总结:

1. 从5中可以看出当我们使用CollectionGenFoo<? extends SuperClass>的通配符方式声明对象引用时,虽然引用可以接受不 同泛型的对象实例,但是该实例泛型的具体类型已经丢失,全部被上溯成为SuperClass类型

 

2.从6中可以看出当我们使用CollectionGenFoo<?>的通配符方式声明对象引用时,虽然引用可以接受不 同泛型的对象实例,但是该实例的泛型的具体类型已经丢失,全部被上溯成为Object类型

 

3.5,6中的  new的实例中的泛型必须是SuperClass的子类或者SuperClass类型。

 

4.通配符泛型不单可以向下限制,还可以向上限制,如:<? Super  ArrayList>,表示类型只能接受ArrayList类型以及其上层父类类型,如:List,Collection

  

  3.泛型方法 

    未完。。。


原文链接:http://lkf520java.iteye.com/blog/734967

阅读更多
个人分类: java基础
上一篇红黑树数据结构剖析
下一篇HashMap和Hashtable的区别
想对作者说点什么? 我来说一句

java Hashtable的泛型

2010年06月21日 59KB 下载

Java泛型和集合.pdf

2011年09月26日 5.39MB 下载

JAVA泛型加减乘除

2014年04月09日 17KB 下载

Java 泛型擦除后的三种补救方法

2009年08月10日 136KB 下载

Java Generics and Collections

2018年05月09日 2.13MB 下载

关于java泛型的讲解

2011年06月15日 63KB 下载

没有更多推荐了,返回首页

关闭
关闭