posts - 8,  comments - 6,  trackbacks - 0

1.4  常用的泛型:使用泛型参数来编写方法 

Java5+

前面的小节介绍了泛型可以简化Java代码并使代码能够防范ClassCastException错误。除了作为JDK的一部分来使用泛型之外,还可以编写你自己的泛型。当对类型相同的对象进行操作时泛型是很有用的,但是对象的具体类型直到对类实例化时才能知道。这种方式非常适合于包含关联项目的集合或涉及查找的类。

下面编写一个使用泛型参数的方法。回想一下前面是怎样使用ArrayList类的—— 只在构造ArrayList时才指定它使用哪些对象类型。注意,在定义类时并不知道其类型,并且不能将java.lang.Object作为类型使用,因为最后将遇到类似以前的类型强制转换问题。当定义泛型时,必须使用一种特殊的语言来代表类型。当声明类名时要完成此操作。在下面的示例中,<T>表示一种类将使用的类型:

 public class RandomSelection<T> { }

这里,类型指示符的尖括号看起来类似HTML语法,但实际上和HTML没有关系,它们也不表示小于或大于!尖括号在一个泛型的类名与一个类型相结合的情况下使用,正如前面的ArrayList<Integer>那样。尽管直到调用构造函数时才知道真实的类型,但我们可以在方法定义中使用替换类型。假定定义了一个叫做RandomSelection的类,该类使用另一个类的某个类型,暂时将该类型称为T。但是,此类的名字仍是RandomSelection。另外,每次可以对多个类型执行这种操作,正如java.util.Map的定义所示的那样。在这种情况下,在类名之后使用一个由逗号分隔的标识符列表即可。

public class MyGeneric<T,U,V> { }

上面定义的MyGeneric类涉及到三个类型,它们分别称为T、U和V。下面编写一个方法来扩展RandomSelection类,该方法将一个项目添加到一个由内部管理的泛型(类型为T)的ArrayList中:

public class RandomSelection<T> {
private ArrayList<T> list;

public RandomSelection() {
list = new ArrayList<T>();
}

public void add(T element) {
list.add(element);
}
}

注意,实际上并不是处理一个叫作T的类。T代表当某人创建RandomSelection的一个实例时使用的任意类。Java规范允许使用任意标识符,但是一般是使用单个大写字母来和普通的类名进行区别。既然已经定义add方法接受一个类型T参数,则只能使用在构造RandomSelection实例时采用的相同的类型来调用此方法。以下的代码是非法的并会产生一个编译错误:
RandomSelection<String> rs = new RandomSelection<String>();
rs.add(new Date()); // illegal for a RandomSelection<String>

如果希望一个方法返回一个泛型类型,可以将方法签名的返回类型设为T,正如下面的定义所示:
import java.util.Random;
public class RandomSelection<T> {
private java.util.Random random = new Random();
// ..... earlier methods omitted

public T getRandomElement() {
int index = random.nextInt(list.size());
return list.get(index);
}
}


getRandomElement方法返回一个类型T,即与在类声明中定义的类型相同。通过构造一个类型实例,现在可以使用刚才定义的RandomSelection类:
RandomSelection<Integer> selector = new RandomSelection<Integer>();
selector.add(2);
selector.add(3);
selector.add(5);
selector.add(7);
selector.add(11);
Integer choice = selector.getRandomElement();
System.out.println(choice);

给一个整型变量choice赋值是安全的,因为selector的getRandomElement方法返回的总是一个Integer。情况确实如此,因为是使用Integer作为泛型类型来构造的selector实例。Add和getRandomElement方法的定义具有和构造函数的定义相同的类型,并且编译器将会强制执行此约束。尝试在构造函数中以一个不同的类型来使用RandomSelection类,这次使用前面定义的Fruit enum类:
RandomSelection<Fruit> fruitSelector = new RandomSelection<Fruit>();
fruitSelector.add(Fruit.APPLE);
fruitSelector.add(Fruit.ORANGE);
fruitSelector.add(Fruit.GRAPEFRUIT);
fruitSelector.add(Fruit.BANANA);
fruitSelector.add(Fruit.DURIAN);
Fruit fruitChoice = fruitSelector.getRandomElement();
System.out.println(fruitChoice);

可以看出,能够直接使用来自getRandomElement方法的Fruit返回值,正如前面对待Integer那样。如果你想要一个类与某种类型(直到构造该类时才知道具体的类型)的对象协同操作以及希望编译器严格执行类型限制,那么你可以定义自己的泛型。这样做的主要优点体现在它的安全和便利性上。若想了解有关泛型的更多信息,请查阅网址http:// java.sun.com/j2se/1.5.0/docs/guide/language/generics.html上的Generics Tutorial(泛型指南) 和Java 5文档。


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


网站导航:
 

<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

留言簿(1)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜