风之语

posts(201) comments(182) trackbacks(1)
  • BlogJava
  • 联系
  • RSS 2.0 Feed 聚合
  • 管理

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论

留言簿

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔分类

  • ajax(1)
  • android(1)
  • apache(1)
  • AppFuse(1)
  • BIRT(1)
  • iText(1)
  • JSF(8)
  • kettle(1)
  • linux(5)
  • mac(1)
  • maven(1)
  • MSTR(3)
  • Open XML(1)
  • Oracle(21)
  • RCP
  • Struts(2)
  • Struts2(2)
  • SybaseIQ(6)
  • tapestry
  • tomcat(2)
  • weblogic(1)
  • webservice(1)
  • weka(1)
  • 云计算(1)
  • 收藏(31)
  • 数据仓库(11)
  • 架构设计(3)
  • 生活(2)
  • 集群(1)
  • 项目管理(6)

随笔档案

  • 2012年12月 (4)
  • 2012年11月 (1)
  • 2012年7月 (2)
  • 2011年8月 (1)
  • 2011年7月 (1)
  • 2011年3月 (1)
  • 2010年12月 (2)
  • 2010年11月 (4)
  • 2010年10月 (3)
  • 2010年9月 (5)
  • 2010年8月 (1)
  • 2010年7月 (4)
  • 2010年3月 (1)
  • 2010年2月 (3)
  • 2009年12月 (3)
  • 2009年11月 (4)
  • 2009年9月 (3)
  • 2009年6月 (5)
  • 2009年5月 (3)
  • 2009年4月 (2)
  • 2009年3月 (5)
  • 2009年2月 (4)
  • 2009年1月 (2)
  • 2008年11月 (2)
  • 2008年9月 (1)
  • 2008年7月 (2)
  • 2008年6月 (4)
  • 2008年5月 (6)
  • 2008年4月 (1)
  • 2008年3月 (1)
  • 2007年12月 (2)
  • 2007年11月 (5)
  • 2007年10月 (2)
  • 2007年9月 (3)
  • 2007年8月 (3)
  • 2007年4月 (1)
  • 2007年3月 (2)
  • 2007年2月 (2)
  • 2007年1月 (2)
  • 2006年12月 (3)
  • 2006年8月 (2)
  • 2006年7月 (2)
  • 2006年6月 (2)
  • 2006年4月 (2)
  • 2006年3月 (1)
  • 2006年2月 (3)
  • 2006年1月 (6)
  • 2005年12月 (6)
  • 2005年11月 (4)
  • 2005年10月 (17)
  • 2005年9月 (25)
  • 2005年8月 (16)
  • 2005年7月 (8)

相册

  • 技术图片

收藏夹

  • java

link

My wife

  • My wife's blog

最新随笔

  • 1. apache修改最大连接并用ab网站压力测试
  • 2. Vm虚拟机访问本地硬盘文件
  • 3. NFS文件无法写入的权限问题
  • 4. weblogic设置上传文件访问权限
  • 5. 在android上动态实现ichartjs的3D柱形图
  • 6. 使用Oracle trunc 来指定精确的年月日时分秒
  • 7. Quartz 2.1.5 web应用配置
  • 8. LoginAny 使用笔记
  • 9. MyEclipse 无响应的几种解决办法
  • 10. java.sql.SQLException: No more data to read from socket

搜索

  •  

积分与排名

  • 积分 - 402239
  • 排名 - 139

最新评论

  • 1. re: 使用Oracle trunc 来指定精确的年月日时分秒[未登录]
  • 政治
  • --张三
  • 2. re: 干掉流氓软件vrvrf_c.exe,vrvedp_m.exe[未登录]
  • `
  • --1
  • 3. re: 无需刻录DMG光盘,教你在VMWare下安装MAC OS X Snow Leopard 10.6
  • 我走到了换DMG映像的时候,然后就没有反应了,这个是什么情况,是不是我的映像文件有问题,还是。。。。
  • --玉竹常青
  • 4. re: LoginAny 使用笔记
  • 怎么没一个人留言,现在来是不是在挖坟啊
  • --ellipse
  • 5. MSTR web应用的部署[未登录]
  • 请问,如何用oracle Application Server服务器部署mstr web应用?
  • --rocky

阅读排行榜

评论排行榜

View Post

Jdk5.0新特性——Generic Types (泛型) (一)

本文摘自fasttalk的blog,觉得还可以加以收藏:
JDK1.5
令我们期待很久,可是当他发布的时候却更换版本号为5.0。这说明Java已经有大幅度的变化。本文将讲解JDK5.0支持的新功能-----Java的泛型.

目录

 

1. 介绍
2. 定义简单Java泛型
3. 泛型通配符
     
3.1有限制的通配符
4.泛型与数据类型转换
  
4.1.消除类型转换
   4.2 自动解包装与自动包装的功能
   4.3
限制泛型中类型参数的范围
5.泛型方法
6.
和遗留代码的交互
     6.1
在泛型代码中使用遗留代码
     6.2
檫除和转换
     6.3
在遗留代码中使用泛型
7
完美的打印
     7.1
泛型类被所有的它的调用所共享
     7.2
转型和InstanceOf
     7.3
数组

8
在运行时类型拖肯的类的表面
9
非常有趣的通配符
     9.1
通配符捕捉
10
使用泛型转换遗留代码

 

1. 介绍

2.
定义简单Java泛型

  其实Java的泛型就是创建一个用类型作为参数的类。就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1、str2的值是可变的。而泛型也是一样的,这样写class Java_Generics<K,V>,这里边的K和V就象方法中的参数str1和str2,也是可变。下面看看例子:


import Java.util.Hashtable;
class TestGen0<K,V>{
  public Hashtable<K,V> h=new Hashtable<K,V>();
  public void put(K k, V v) {
   h.put(k,v);
  }
  public V get(K k) {
   return h.get(k);
  }
  public static void main(String args[]){
   TestGen0<String,String> t=new TestGen0<String,String>();
   t.put("key", "value");
   String s=t.get("key");
   System.out.println(s);
  }
}

正确输出:value

   这只是个例子,不过看看是不是创建一个用类型作为参数的类,参数是K,V,传入的“值”是String类型。这个类他没有特定的待处理型别,以前我们定义好了一个类,在输入参数有所固定,是什么型别的有要求,但是现在编写程序,完全可以不制定参数的类型,具体用的时候来确定,增加了程序的通用性,像是一个模板。


3.1有限制的通配符

考虑一个画图的应用程序,这个程序能够画长方形、圆等类型,为了在程序中表示这样的图形,你可以定义一个类型的层次结构:

public abstract class Shape{

         public abstract void draw(Canvas c);

 }

public class Circle extends Shape{

         private int x,y,radius;

         public void draw(Canvas c){}

}

public class Rectangle extends Shape{

         private int x,y,width,height;

         public void draw(Canvas c){

}

}

//这些类能被画在画布上:

public class Canvas{

       public void draw(Shape s){

                s.draw(this);

       }

}

 

任何画图的动作的都包含一些图形,假设他们被表示在一个list中,在Canvas中它将会有一个很方便的方法来画他们:

   public void drawAll(List<Shape> shapes){

             for(Shape s :shapes){

               s.draw(this);

              }

   }

    现在类型规则说,方法drawAll()只能在真正的Shape类型的List上被调用,而它的子类无法调用,例如List<Circle>上被调用。这是很不幸的。由于所有的方法确实从List中读出Shape,所以它仅能在List<Object>上被调用,下面我们改后的代码可以在任意类型的Shape上被调用:

public void drawAll(List< ? extends Shape>{ }

这里有一个很小的不同是,我们已经用List<? extends Shape>替换了List<Object>,现在drawAll()方法可以接受任意的Shape的子类了,我们当然可以在List<Circle>上调用。  

   <? extends Class>是一种限制通配符类型,它可以接受所有<Class>以及Class的子类型。然而调用代价是,只读访问,无法向shapes中添加元素。像通常一样,使用通配符带来的灵活性将付出代价,例如,下面是不允许的:

   public void addRectangle(List<? extends Shape> shapes){

     shapes.add(0,new Rectangle());//编译时错误

   }

    限制性通配符的一个例子是,是一个人口普查的例子,我们假设数据是由一个名字映射一个人,名字是字符串,人(可以是Person,或是它的子类Driver),Map<k,v>是一个泛型的例子,它拥有两个参数,表示为一个KEY和value的映射MAP

   再次注意正规参数的命名规则,K代表key,V代表value

     public class Census{

        public static void addRegistry(Map<String ? extends Person> Registry){ }

     }

    Map<String,Driver>  allDrivers =;

    census.addResigtry(allDrivers);


编写泛型类要注意:
   1) 在定义一个泛型类的时候,在 “<>”之间定义形式类型参数,例如:“class TestGen<K,V>”,其中“K” , “V”不代表值,而是表示类型。
   2) 实例化泛型对象的时候,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。例如:
TestGen<String,String> t=new TestGen<String,String>()
;
   3) 泛型中<K extends Object>,extends并不代表继承,它是类型范围限制。

4.泛型与数据类型转换
4.1.
消除类型转换
   上面的例子大家看到什么了,数据类型转换的代码不见了。在以前我们经常要书写以下代码,如:

import Java.util.Hashtable;
class Test {
  public static void main(String[] args) {
   Hashtable h = new Hashtable();
   h.put("key", "value");
   String s = (String)h.get("key");
   System.out.println(s);
  }
}

   这个我们做了类型转换,是不是感觉很烦的,并且强制类型转换会带来潜在的危险,系统可能会抛一个ClassCastException异常信息。在JDK5.0中我们完全可以这么做,如:

import Java.util.Hashtable;
class Test {
  public static void main(String[] args) {
   Hashtable<String,Integer> h = new Hashtable<String,Integer> ();
   h.put("key", new Integer(123));
   int s = h.get("key").intValue();
   System.out.println(s);
  }
}

   这里我们使用泛化版本的HashMap,这样就不用我们来编写类型转换的代码了,类型转换的过程交给编译器来处理,是不是很方便,而且很安全。上面是String映射到String,也可以将Integer映射为String,只要写成HashTable<Integer,String> h=new HashTable<Integer,String>();h.get(new Integer(0))返回value。果然很方便。

4.2
自动解包装与自动包装的功能
  从上面有没有看到有点别扭啊,h.get(new Integer(123))这里的new Integer(123);好烦的,在JDK5.0之前我们只能忍着了,现在这种问题已经解决了,请看下面这个方法。我们传入一个int这一基本型别,然后再将i的值直接添加到List中,其实List是不能储存基本型别的,List中应该存储对象,这里编译器将int包装成Integer,然后添加到List中去。接着我们用List.get(0);来检索数据,并返回对象再将对象解包装成int。恩,JDK5.0给我们带来更多方便与安全。

public void autoBoxingUnboxing(int i) {
  ArrayList<Integer> L= new ArrayList<Integer>();
  L.add(i);
  int a = L.get(0);
  System.out.println("The value of i is " + a);
}

4.3 限制泛型中类型参数的范围
  也许你已经发现在TestGen<K,V>这个泛型类,其中K,V可以是任意的型别。也许你有时候呢想限定一下K和V当然范围,怎么做呢?看看如下的代码:

class TestGen2<K extents String,V extends Number>
{
  private V v=null;
  private K k=null;
  public void setV(V v){
   this.v=v;
  }
  public V getV(){
   return this.v;
  }
  public void setK(K k){
   this.k=k;
  }
  public V getK(){
   return this.k;
  }
  public static void main(String[] args)
  {
   TestGen2<String,Integer> t2=new TestGen2<String,Integer>();
   t2.setK(new String("String"));
   t2.setV(new Integer(123));
   System.out.println(t2.getK());
   System.out.println(t2.getV());
  }
}

   上边K的范围是<=String ,V的范围是<=Number,注意是“<=”,对于K可以是String的,V当然也可以是Number,也可以是Integer,Float,Double,Byte等。看看下图也许能直观些请看上图A是上图类中的基类,A1,A2分别是A的子类,A2有2个子类分别是A2_1,A2_2。

   然后我们定义一个受限的泛型类class MyGen<E extends A2>,这个泛型的范围就是上图中兰色部分。

   这个是单一的限制,你也可以对型别多重限制,如下:

class C<T extends Comparable<? super T> & Serializable>
   我们来分析以下这句,T extends Comparable这个是对上限的限制,Comparable< super T>这个是下限的限制,Serializable是第2个上限。一个指定的类型参数可以具有一个或多个上限。具有多重限制的类型参数可以用于访问它的每个限制的方法和域。

5.泛型方法

考虑写一个持有数组类型对象和一个集合对象的方法,把数组里的所有对象都放到

集合里。第一个程序为:

   static void fromArrayToColleciton(Object[]a,Collection<?> c){

     for (Object o : a){

        c.add(o);//编译时错误

        }

   }

到现在为止,你可能学会避免开始的错误而去使用Collection<Object>作为集合参数的类型,你可能会意识到使用Colleciton<?>将不会工作。

解决这个问题的方法是使用泛型方法,GENERIC METHODS,就像类型声明、方法声明一样,就是被一个或更多的类型参数参数化。

   static <T> void fromArrayToCollection(T[]a,Collection<T> c){

        for(T o :a){

             c.add(o);//正确

            }

   }

    我们可以用任意类型的集合调用这个方法,他的元素类型是数组元素类型的超类型。

   Object[] oa = new Object[100];

   Collection <Object> co = new ArrayList<Object>();

   fromArrayToCollection(oa,co);//T 被认为是Object类型

   String[] sa = new String[100];

   Colleciton<String> cs = new ArrayList<String>();

   fromArrayToCollection(sa,cs);//T被认为是String类型

   fromArrayToCollection(sa,co);//T 被认为是Object类型

   Integer[] is = new Integer[100];

   Float[] fa = new Float[100];

   Number[] na = new Number[100];

   Collection<Number> cn = new ArrayList<Number>(); 

   fromArrayToCollection(is,cn);//Number

   fromArrayToCollection(fa,cn);//Number

   fromArrayToCollection(na,cn);//Number

   fromArrayToCollection(na,co);//Object

   fromArrayToCollection(na,cs);//编译时错误

我们不必给一个泛型方法传递一个真正的类型参数,编译器会推断类型参数.一个问题出现了,什么时候使用泛型方法,什么时候使通配符类型,为了回答这些问题,我们从Colleciton库中看一下几个方法:

    interface Collection<E>{

           public boolean containsAll(Collection<?> c);

           public boolean addAll(Collection<? extends E> c);

    }

    使用泛型方法的形式为:

    interface Collection<E>{

           public <T> boolean containsAll(Collection<T> c);

           public <T extends E> boolean addAll(Collection<T> c);

    } 

   无论如何,在ContainAll和addAll中,类型参数T仅被使用一次。返回类型不依赖于类型参数,也不依赖方法中的任何参数。这告诉我类型参数正被用于多态,它的影响仅仅是允许不同的实参在不同的调用点被使用。

   泛型方法允许类型参数被用于表达在一个或更多参数之间或者方法中的参数、返回类型的依赖。如果没有如此依赖,泛型方法就不能被使用。可能一前一后来联合使用泛型和通配符,这里有个例子:

    class Collections{

      public static <T> void copy(List<T> dest,List<? extends T> src){

    }

  }

    注意两个参数之间的依赖,任何从原list的对象复制,必须分配一个目标LIST元素的类型T,于是Src的元素类型可能是任何T的子类型。我们不必在意在COPY的表达中,表示依赖使用一个类型参数,但是是使用一个通配符。

    下面我们不使用通配符来重写上面的方法:

     class Collections{

      public static <T,S extends T>

      void copy(List<T> dest,List<S> src){

    }

  } 

    这非常好,但是第一个类型参数既在dst中使用,也在第二个类型参数中使用,S本身就被使用了一次。在类型src中,没有什么类型依赖它。这是一个标志我们可以用通配符来替换它。使用通配符比显示的声明类型参数更加清楚和精确。所以有可能推荐使用通配符。

   通配符也有优势,可以在方法之外来使用,作为字段类型、局部变量和数组。

这里有一个例子。

   返回到我们画图的例子,假设我们要保持一个画图请求的历史,我们可以在Shape类内部用一个静态变量来保持历史。用drawAll()存储它到来的参数到历史字段。

   static List<List<? extends Shape>> history =

   new ArrayList<List<? extends Shape>>();

   public void drawAll(List<? extends Shape> shapes){

    history.addLast(shapes);

    for (Shape s : shapes){

           s.draw(this);

         }

   }      

posted on 2005-08-11 23:39 风 阅读(1424) 评论(2)  编辑  收藏

View Comments

# re: Jdk5.0新特性——Generic Types (泛型) (一)  回复  更多评论   
学习了!

交待的非常清楚,请继续!!
2005-08-12 00:47 | 左光
# 楼主有调过自己贴的代码吗?  回复  更多评论   
>>import Java.util.Hashtable;

Java这个包是楼主自己写的吧?我只知道有个java.util.Hashtable

>>Map allDrivers =; 这也能编译通过?
2005-08-12 09:14 | emu
新用户注册  刷新评论列表  

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问   管理
 
 
Powered by:
BlogJava
Copyright © 风