选择显示字体大小

java 范型攻略篇

作者:管斌(苏州星动) blog:(http://blog.matrix.org.cn/page/guanbing)

在已发布的java1.4中在核心代码库中增加了许多新的api(如loging,正则表达式,nio)等,在最新发布的jdk1.5和即将发布的jdk1.6中也新增了许多api,其中比较有重大意义的就是generics(范型)。

一.什么是generics?

generics可以称之为参数类型(parameterized types),由编译器来验证从客户端将一种类型传送给某一对象的机制。如java.util.arraylist,

编译器可以用generics来保证类型安全
在我们深入了解generics之前,我们先来看一看当前的java 集合框架(collection)。在j2se1.4中所有集合的root interface是collection

collections example without genericity: example 1


1 protected void collectionsexample() {
2  arraylist list = new arraylist();
3  list.add(new string("test string"));
4  list.add(new integer(9)); // purposely placed here to create a runtime classcastexception
5  inspectcollection(list);
6 }
7
8
9 protected void inspectcollection(collection acollection) {
10  iterator i = acollection.iterator();
11  while (i.hasnext()) {
12   string element = (string) i.next();
13  }
14 }


以上的样例程序包含的两个方法,collectionexample方法建立了一个简单的集合类型arraylist,并在arraylist中增加了一个string和一个integer对象.而在inspeccollection方法中,我们迭代这个arraylist用string进行cast。我们看第二个方法,就出现了一个问题,collection在内部用的是object,而我们要取出collection中的对象时,需要进行cast,那么开发者必需用实际的类型进行cast,像这种向下造型,编译器无

法进行检查,如此一来我们就要冒在代码在运行抛出classcastexception的危险。我们看inspeccollection方法,编译时没有问题,但在运行时就会抛出classcastexception异常。所以我们一定要远离这个重大的运行时错误


二.使用generics
从上一章节中的casscastexception这种异常,我们期望在代码编译时就能够捕捉到,下面我们使用范型修改上一章的样例程序。
//example 2
1 protected void collectionsexample() {
2  arraylist<string> list = new arraylist<string>();
3  list.add(new string(&quot;test string&quot;));
4  // list.add(new integer(9)); this no longer compiles
5  inspectcollection(list);
6 }
7
8
9 protected void inspectcollection(collection<string> acollection) {
10  iterator<string> i = acollection.iterator();
11  while(i.hasnext()) {
12   string element = i.next();
13  }
14 }


从上面第2行我们在创建arraylist时使用了新语法,在jdk1.5中所有的collection都加入了generics的声明。例:
//example 3
1 public class arraylist<e> extends abstractlist<e> {
2  // details omitted...
3  public void add(e element) {
4   // details omitted
5  }
6  public iterator<e> iterator() {
7   // details omitted
8  }
9 }


这个e是一个类型变量,并没有对它进行具体类型的定义,它只是在定义arraylist时的类型占位符,在example 2中的我们在定义arraylist的实

例时用string绑定在e上,当我们用add(e element)方法向arraylist中增加对象时, 那么就像下面的写法一样: public void add(string element);因为在arraylist所有方法都会用string来替代e,无论是方法的参数还是返回值。这时我们在看example 2中的第四行,编译就会反映出编译错误。
所以在java中增加generics主要的目的是为了增加类型安全

通过上面的简单的例子我们看到使用generics的好处有:
1.在类型没有变化时,collection是类型安全的。
2.内在的类型转换优于在外部的人工造型。
3.使java 接口更加强壮,因为它增加了类型。
4.类型的匹配错误在编译阶段就可以捕捉到,而不是在代码运行时。

受约束类型变量
虽然许多class被设计成generics,但类型变量可以是受限的
public class c1<t extends number> { }
public class c2<t extends person & comparable> { }
第一个t变量必须继承number,第二个t必须继承person和实现comparable

三.generics 方法

像generics类一样,方法和构造函数也可以有类型参数。方法的参数的返回值都可以有类型参数,进行generics。
//example 4
1 public <t extends comparable> t max(t t1, t t2) {
2  if (t1.compareto(t2) > 0)
3   return t1;
4  else return t2;
5 }


这里,max方法的参数类型为单一的t类型,而t类型继承了comparable,max的参数和返回值都有相同的超类。下面的example 5显示了max方法的几个约束。
//example 5 
1 integer iresult = max(new integer(100), new integer(200));
2 string sresult = max(&quot;aa&quot;, &quot;bb&quot;);
3 number nresult = max(new integer(100), &quot;aaa&quot;); // does not compile


在example 5第1行参数都为integer,所以返回值也是integer,注意返回值没有进行造型。
在example 5第2行参数都为string,所以返回值也是string,注意返回值没有进行造型。以上都调用了同一个方法。
在example 5第3行产生以下编译错误:
example.java:10: incompatible types
found  : java.lang.object&java.io.serializable&java.lang.comparable<?>
required: java.lang.number
    number nresult = max(new integer(100), &quot;aaa&quot;);


这个错误发生是因为编译器无法确定返回值类型,因为string和integer都有相同的超类object,注意就算我们修正了第三行,这行代码在运行仍然会报错,因为比较了不同的对象。

四.向下兼容
任何一个新的特色在新的jdk版本中出来后,我们首先关心的是如何于以前编写的代码兼容。也就是说我们编写的example 1程序不需要任何的改变就可以运行,但是编译器会给出一个&quot;row type&quot;的警告。在jdk1.4中编写的代码如何在jvm1.5中完全兼容运行,我们要人工进行一个:type erasure处理过程

五.通配符

//example 6
list<string> stringlist = new arraylist<string>(); //1
list<object> objectlist = stringlist ;//2
objectlist .add(new object()); // 3
string s = stringlist .get(0);//4


乍一看,example

6是正确的。但stringlist本意是存放string类型的arraylist,而objectlist中可以存入任何对象,当在第3行进行处理时,stringlist也就无法保证是string类型的arraylist,此时编译器不允许这样的事出现,所以第3行将无法编译。

//example 7
void printcollection(collection<object> c) 
{ for (object e : c) {
system.out.println(e);
}}


example 7的本意是打印所有collection的对象,但是正如example 6所说的,编译会报错,此时就可以用通配符&ldquo;?&rdquo;来修改example 7

//example 8
void printcollection(collection<?> c) 
{ for (object e : c) {
system.out.println(e);
}}


example 8中所有collection类型就可以方便的打印了

有界通配符 <t extends number>(上界) <t super number>(下界)

六.创建自己的范型
以下代码来自http://www.java2s.com/examplecode/language-basics
1.一个参数的generics
//example 9(没有使用范型)
class nongen {  
  object ob; // ob is now of type object
  // pass the constructor a reference to  
  // an object of type object
  nongen(object o) {  
    ob = o;  
  }  
  // return type object.
  object getob() {  
    return ob;  
  }  
  // show type of ob.  
  void showtype() {  
    system.out.println(&quot;type of ob is &quot; +  
                       ob.getclass().getname());  
  }  
}  
// demonstrate the non-generic class.  
public class nongendemo {  
  public static void main(string args&#91;&#93;) {  
    nongen iob;  
    // create nongen object and store
    // an integer in it. autoboxing still occurs.
    iob = new nongen(88);  
    // show the type of data used by iob.
    iob.showtype();
    // get the value of iob.
    // this time, a cast is necessary.
    int v = (integer) iob.getob();  
    system.out.println(&quot;value: &quot; + v);  
    system.out.println();  
    // create another nongen object and  
    // store a string in it.
    nongen strob = new nongen(&quot;non-generics test&quot;);  
    // show the type of data used by strob.
    strob.showtype();
    // get the value of strob.
    // again, notice that a cast is necessary.  
    string str = (string) strob.getob();  
    system.out.println(&quot;value: &quot; + str);  
    // this compiles, but is conceptually wrong!
    iob = strob;
    v = (integer) iob.getob(); // runtime error!
  }  
}
  

//example 10(使用范型)
class example1<t>{
private t t;
example1(t o){
  this.t=o;
  }
t getob(){
  return t;
}
void showobject(){
  system.out.println(&quot;对象的类型是:&quot;+t.getclass().getname());
}
}
public class genericsexample1 {

/**
  * @param args
  */
public static void main(string&#91;&#93; args) {
  // todo auto-generated method stub
  example1<integer> examplei=new example1<integer>(100);
  examplei.showobject();
  system.out.println(&quot;对象是:&quot;+examplei.getob());
  example1<string> examples=new example1<string>(&quot;bill&quot;);
  examples.showobject();
  system.out.println(&quot;对象是:&quot;+examples.getob());
}

}


我们来看example 9没有使用范型,所以我们需要进行造型,而example 10我们不需要任何的造型

2.二个参数的generics

//example 11
class twogen<t, v> { 
   t ob1;
   v ob2;
   // pass the constructor a reference to  
   // an object of type t.
   twogen(t o1, v o2) {
     ob1 = o1;
     ob2 = o2;
   }
   // show types of t and v.
   void showtypes() {
     system.out.println(&quot;type of t is &quot; +
                        ob1.getclass().getname());
     system.out.println(&quot;type of v is &quot; +
                        ob2.getclass().getname());
   }
   t getob1() {
     return ob1;
   }
   v getob2() {
     return ob2;
   }
}

public class genericsexamplebytwoparam {

/**
  * @param args
  */
public static void main(string&#91;&#93; args) {
  // todo auto-generated method stub
  twogen<integer, string> tgobj =
       new twogen<integer, string>(88, &quot;generics&quot;);
     // show the types.
     tgobj.showtypes();
     // obtain and show values.
     int v = tgobj.getob1();
     system.out.println(&quot;value: &quot; + v);
     string str = tgobj.getob2();
     system.out.println(&quot;value: &quot; + str);
   }

}


3.generics的hierarchy

//example 12
class stats<t extends number> {  
   t&#91;&#93; nums; // array of number or subclass
   // pass the constructor a reference to  
   // an array of type number or subclass.
   stats(t&#91;&#93; o) {  
     nums = o;  
   }  
   // return type double in all cases.
   double average() {  
     double sum = 0.0;
     for(int i=0; i < nums.length; i++)  
       sum += nums&#91;i&#93;.doublevalue();
     return sum / nums.length;
   }  
}  
public class genericsexamplebyhierarchy {


/**
  * @param args
  */
public static void main(string&#91;&#93; args) {
  // todo auto-generated method stub

   integer inums&#91;&#93; = { 1, 2, 3, 4, 5 };
     stats<integer> iob = new stats<integer>(inums);  
     double v = iob.average();
     system.out.println(&quot;iob average is &quot; + v);
     double dnums&#91;&#93; = { 1.1, 2.2, 3.3, 4.4, 5.5 };
     stats<double> dob = new stats<double>(dnums);  
     double w = dob.average();
     system.out.println(&quot;dob average is &quot; + w);
     // this won't compile because string is not a
     // subclass of number.
//     string strs&#91;&#93; = { &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot; };
//     stats<string> strob = new stats<string>(strs);  
//     double x = strob.average();
//     system.out.println(&quot;strob average is &quot; + v);
   }  
}
  

4.使用通配符
//example 14
class statswildcard<t extends number> {
t&#91;&#93; nums; // array of number or subclass
// pass the constructor a reference to
// an array of type number or subclass.
statswildcard(t&#91;&#93; o) {
  nums = o;
}
// return type double in all cases.
double average() {
  double sum = 0.0;
  for (int i = 0; i < nums.length; i++)
   sum += nums&#91;i&#93;.doublevalue();
  return sum / nums.length;
}
// determine if two averages are the same.
// notice the use of the wildcard.
boolean sameavg(statswildcard<?> ob) {
  if (average() == ob.average())
   return true;
  return false;
}
}

public class genericsexamplebywildcard {

/**
  * @param args
  */
public static void main(string&#91;&#93; args) {
  // todo auto-generated method stub
  integer inums&#91;&#93; = { 1, 2, 3, 4, 5 };
  statswildcard<integer> iob = new statswildcard<integer>(inums);
  double v = iob.average();
  system.out.println(&quot;iob average is &quot; + v);
  double dnums&#91;&#93; = { 1.1, 2.2, 3.3, 4.4, 5.5 };
  statswildcard<double> dob = new statswildcard<double>(dnums);
  double w = dob.average();
  system.out.println(&quot;dob average is &quot; + w);
  float fnums&#91;&#93; = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
  statswildcard<float> fob = new statswildcard<float>(fnums);
  double x = fob.average();
  system.out.println(&quot;fob average is &quot; + x);
  // see which arrays have same average.
  system.out.print(&quot;averages of iob and dob &quot;);
  if (iob.sameavg(dob))
   system.out.println(&quot;are the same.&quot;);
  else
   system.out.println(&quot;differ.&quot;);
  system.out.print(&quot;averages of iob and fob &quot;);
  if (iob.sameavg(fob))
   system.out.println(&quot;are the same.&quot;);
  else
   system.out.println(&quot;differ.&quot;);

}

}


5.使用边界通配符
//example 15
class twod { 
  int x, y;
  twod(int a, int b) {
    x = a;
    y = b;
  }
}
// three-dimensional coordinates.
class threed extends twod {
  int z;
  threed(int a, int b, int c) {
    super(a, b);
    z = c;
  }
}
// four-dimensional coordinates.
class fourd extends threed {
  int t;
  fourd(int a, int b, int c, int d) {
    super(a, b, c);
    t = d;  
  }
}
// this class holds an array of coordinate objects.
class coords<t extends twod> {
  t&#91;&#93; coords;
  coords(t&#91;&#93; o) { coords = o; }
}
// demonstrate a bounded wildcard.
public class boundedwildcard {
  static void showxy(coords<?> c) {
    system.out.println(&quot;x y coordinates:&quot;);
    for(int i=0; i < c.coords.length; i++)
      system.out.println(c.coords&#91;i&#93;.x + &quot; &quot; +
                         c.coords&#91;i&#93;.y);
    system.out.println();
  }
  static void showxyz(coords<? extends threed> c) {
    system.out.println(&quot;x y z coordinates:&quot;);
    for(int i=0; i < c.coords.length; i++)
      system.out.println(c.coords&#91;i&#93;.x + &quot; &quot; +
                         c.coords&#91;i&#93;.y + &quot; &quot; +
                         c.coords&#91;i&#93;.z);
    system.out.println();
  }
  static void showall(coords<? extends fourd> c) {
    system.out.println(&quot;x y z t coordinates:&quot;);
    for(int i=0; i < c.coords.length; i++)
      system.out.println(c.coords&#91;i&#93;.x + &quot; &quot; +
                         c.coords&#91;i&#93;.y + &quot; &quot; +
                         c.coords&#91;i&#93;.z + &quot; &quot; +
                         c.coords&#91;i&#93;.t);
    system.out.println();
  }
  public static void main(string args&#91;&#93;) {
    twod td&#91;&#93; = {
      new twod(0, 0),
      new twod(7, 9),
      new twod(18, 4),
      new twod(-1, -23)
    };
    coords<twod> tdlocs = new coords<twod>(td);    
    system.out.println(&quot;contents of tdlocs.&quot;);
    showxy(tdlocs); // ok, is a twod
//  showxyz(tdlocs); // error, not a threed
//  showall(tdlocs); // erorr, not a fourd
    // now, create some fourd objects.
    fourd fd&#91;&#93; = {
      new fourd(1, 2, 3, 4),
      new fourd(6, 8, 14, 8),
      new fourd(22, 9, 4, 9),
      new fourd(3, -2, -23, 17)
    };
    coords<fourd> fdlocs = new coords<fourd>(fd);    
    system.out.println(&quot;contents of fdlocs.&quot;);
    // these are all ok.
    showxy(fdlocs);  
    showxyz(fdlocs);
    showall(fdlocs);
  }
}



6.arraylist的generics
//example 16
public class arraylistgenericdemo {
  public static void main(string&#91;&#93; args) {
    arraylist<string> data = new arraylist<string>();
    data.add(&quot;hello&quot;);
    data.add(&quot;goodbye&quot;);

    // data.add(new date()); this won't compile!

    iterator<string> it = data.iterator();
    while (it.hasnext()) {
      string s = it.next();
      system.out.println(s);
    }
  }
}


7.hashmap的generics
//example 17
public class hashdemogeneric {
  public static void main(string&#91;&#93; args) {
    hashmap<integer,string> map = new hashmap<integer,string>();

    map.put(1, &quot;ian&quot;);
    map.put(42, &quot;scott&quot;);
    map.put(123, &quot;somebody else&quot;);

    string name = map.get(42);
    system.out.println(name);
  }
}


8.接口的generics
//example 18
interface minmax<t extends comparable<t>> { 
  t min();
  t max();
}
// now, implement minmax
class myclass<t extends comparable<t>> implements minmax<t> {
  t&#91;&#93; vals;
  myclass(t&#91;&#93; o) { vals = o; }
  // return the minimum value in vals.
  public t min() {
    t v = vals&#91;0&#93;;
    for(int i=1; i < vals.length; i++)
      if(vals&#91;i&#93;.compareto(v) < 0) v = vals&#91;i&#93;;
    return v;
  }
  // return the maximum value in vals.
  public t max() {
    t v = vals&#91;0&#93;;
    for(int i=1; i < vals.length; i++)
      if(vals&#91;i&#93;.compareto(v) > 0) v = vals&#91;i&#93;;
    return v;
  }
}
public class genifdemo {
  public static void main(string args&#91;&#93;) {
    integer inums&#91;&#93; = {3, 6, 2, 8, 6 };
    character chs&#91;&#93; = {'b', 'r', 'p', 'w' };
    myclass<integer> iob = new myclass<integer>(inums);
    myclass<character> cob = new myclass<character>(chs);
    system.out.println(&quot;max value in inums: &quot; + iob.max());
    system.out.println(&quot;min value in inums: &quot; + iob.min());
    system.out.println(&quot;max value in chs: &quot; + cob.max());
    system.out.println(&quot;min value in chs: &quot; + cob.min());
  }
}


9.exception的generics
//example 20
interface executor<e extends exception> {
    void execute() throws e;
}

public class genericexceptiontest {
    public static void main(string args&#91;&#93;) {
        try {
            executor<ioexception> e =
                new executor<ioexception>() {
                public void execute() throws ioexception
                {
                    // code here that may throw an
                    // ioexception or a subtype of
                    // ioexception
                }
            };

            e.execute();
        } catch(ioexception ioe) {
            system.out.println(&quot;ioexception: &quot; + ioe);
            ioe.printstacktrace();
        }
    }
}  


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons