Chinaunix首页 | 论坛 | 博客
  • 博客访问: 405901
  • 博文数量: 38
  • 博客积分: 1490
  • 博客等级: 上尉
  • 技术积分: 406
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-08 00:52
文章分类

全部博文(38)

文章存档

2014年(1)

2013年(1)

2008年(6)

2007年(7)

2006年(23)

我的朋友

分类: Java

2007-05-20 11:09:53

Java1.5泛型指南中文版(Java1.5 Generic Tutorial)

英文版pdf下载链接:

                                   译者:  

         

(第二部分)

 

原文地址http://blog.csdn.net/explorers/archive/2005/08/15/454837.aspx

(Wildcards)

考虑写一个例程来打印一个集合(Collection)中的所有元素。下面是在老的语言中你可能写的代码:

            void printCollection(Collection c) {

                 Iterator i = c.iterator();

                 for (int k = 0; k < c.size(); k++) {

                       System.out.println(i.next());

                  }

} 

下面是一个使用泛型的幼稚的尝试(使用了新的循环语法):

      void printCollection(Collection c) {

           for (Object e : c) {

                 System.out.println(e);

           }

} 

问题是新版本的用处比老版本小多了。老版本的代码可以使用任何类型的collection作为参数,而新版本则只能使用Collection,我们刚才阐述了,它不是所有类型的collections的父类。

那么什么是各种collections父类呢?它写作: Collection>(发音为:"collection of unknown"),就是,一个集合,它的元素类型可以匹配任何类型。显然,它被称为通配符。我们可以写:

void printCollection(Collection c) {

for (Object e : c) {

System.out.println(e);

}

}

现在,我们可以使用任何类型的collection来调用它。注意,我们仍然可以读取c中的元素,其类型是Object。这永远是安全的,因为不管collection的真实类型是什么,它包含的都是objects。但是将任意元素加入到其中不是类型安全的:

Collection c = new ArrayList>();

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

因为我们不知道c的元素类型,我们不能向其中添加对象。

add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。唯一的例外是null,它是所有类型的成员。

另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object,因此把get的返回值赋值给一个Object类型的对象或者放在任何希望是Object类型的地方是安全的。

(Bounded Wildcards)

考虑一个简单的画图程序,它可以用来画各种形状,比如矩形和圆形。

为了在程序中表示这些形状,你可以定义下面的类继承结构:

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) {

// ...

}

}

这些类可以在一个画布(Canvas)上被画出来:

public class Canvas {

public void draw(Shape s) {

s.draw(this);

}

}

所有的图形通常都有很多个形状。假定它们用一个list来表示,Canvas里有一个方法来画出所有的形状会比较方便:

      public void drawAll(List shapes) {

          for (Shape s : shapes) {

             s.draw(this);

         }

}

现在,类型规则导致drawAll()只能使用Shapelist来调用。它不能,比如说对List来调用。这很不幸,因为这个方法所作的只是从这个list读取shape,因此它应该也能对List调用。我们真正要的是这个方法能够接受一个任意种类的shape:

public void drawAll(Listextends Shape> shapes) { //..}

这里有一处很小但是很重要的不同:我们把类型 List 替换成了 Listextends Shape>。现在drawAll()可以接受任何Shape的子类的List,所以我们可以对List进行调用。

List extends Shape>是有限制通配符的一个例子。这里?代表一个未知的类型,就像我们前面看到的通配符一样。但是,在这里,我们知道这个未知的类型实际上是Shape的一个子类(它可以是Shape本身或者Shape的子类而不必是extendsShape)。我们说Shape是这个通配符的上限(upper bound)

像平常一样,要得到使用通配符的灵活性有些代价。这个代价是,现在像shapes中写入是非法的。比如下面的代码是不允许的:

         public void addRectangle(Listextends Shape> shapes) {

       shapes.add(0, new Rectangle()); // compile-time error!

    }

你应该能够指出为什么上面的代码是不允许的。因为shapes.add的第二个参数类型是? extends Shape ——一个Shape未知的子类。因此我们不知道这个类型是什么,我们不知道它是不是Rectangle的父类;它可能是也可能不是一个父类,所以这里传递一个Rectangle不安全。

有限制的通配符正是我们解决DMV给人口普查局传送名单的例子所需要的。我们的例子假定数据用一个姓名(String)到people(用Person或其子类来表示,比如Driver)。Map是一个有两个类型参数的泛型类型的例子,表示map的键key和值value

再一次,注意形式类型参数的命名习惯——K代表keysV代表vlaues

public class Census {

public static void  addRegistry(Map<String, ? extends Person> registry) { ...}

}...

Map<String, Driver> allDrivers = ...;

Census.addRegistry(allDrivers);

 

<未完...请看第三部分>

阅读(2325) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~