java 泛型学习笔记

转载 2015年07月07日 09:31:25

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李兴华学习笔记之泛型

  • 2012年09月07日 09:41
  • 255KB
  • 下载

Java 泛型学习笔记(一)

泛型:Generics 泛型是JDK1.5中的新特性。 没有使用泛型时,只要是对象,不管什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能...

java 泛型学习笔记

//首先我对泛型的理解就是可以把任何Object的子类当做类中的类型,下面是对于泛型的基本定义 public class GenericT {//泛型可接受类型是 Object 的 子类 pri...

JAVA泛型详解 --- 学习笔记

原文请戳此处!!! 1. 2. 3. 4.

Java泛型--学习笔记

1  泛型参数的一些约定 类型参数使用大写类型,且较短。在Java库中,使用变量E表示集合的元素类型,K和V表示关键字和值的类型。T(需要时还可以用临近的U和S)表示“任意类型”。 2  泛型定义 ...

(34)Java学习笔记——集合框架 / 泛型

泛型: 是一种吧类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。 格式: 此处的数据类型只能是引用类型。 好处: A/ 把运行时期的问题提前...

Java学习笔记——链表的泛型实现和序列化读写

Java中的泛型即可参数化类型,在定义类的过程中,可对一些同样类型成员函数和成员变量设置为虚定义类型,在具体调用的时候可以按自己的需要设置为自己所需要的类型,如类标LinkedList中,T即为泛型,...
  • acm2014
  • acm2014
  • 2014年12月18日 16:05
  • 753

黑马程序员Java学习笔记之泛型Generic

一、基本要点      1、 泛型:JDK1.5以后出现的新特性。用以解决安全问题,是一个类型安全机制。      2、格式:           通过      3、好处:           1)...

《Java编程思想》学习笔记8——泛型编程高级

1.泛型边界: Java泛型编程时,编译器忽略泛型参数的具体类型,认为使用泛型的类、方法对Object都适用,这在泛型编程中称为类型信息檫除。 例如: [java] view...

Java 泛型学习笔记

参考来自:   http://www.weixueyuan.net/view/6321.html        ;              http://www.yiibai.com/java/ja...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java 泛型学习笔记
举报原因:
原因补充:

(最多只允许输入30个字)