ITEEDU

Java Gossip: 没有泛型之前

考虑您要设计下面的两个类别(两个很无聊的类别,但足以说明需求):

BooleanFoo.java
public class BooleanFoo {
	private Boolean foo;
	public void setFoo(Boolean foo) {
		this.foo = foo;
	}
	public Boolean getFoo() {
		return foo;
	}
}
IntegerFoo.java
public class IntegerFoo {
	private Integer foo;
	public void setFoo(Integer foo) {
		this.foo = foo;
	}
	public Integer getFoo() {
		return foo;
	}
}

类别定义时逻辑完全一样,只是当中宣告的成员型态不同,有点小聪明的程序设计人员会将第一个类的内容复制至另一个档案中,然后用编辑器「取代」功能一次取 代所有的型态名称(即将Boolean取代为Integer)。

OK!是有些小聪明,但还是不太聪明,如果类别中的逻辑要修改,您要修改两个档案,泛型(Generics)的需求就在此产生,当您定义类 别时,发现到好几个类别的逻辑其实都相同,就只是当中所涉及的型态不一样时,使用复制、贴上、取代的功能来撰写程序只是让您增加不必要的档案管理困扰,有 没有办法只写一个档案就好,毕竟它们的逻辑是相同的。

别忘了,Java中所有的类别都扩充自Object,这样写会比较好:

ObjectFoo.java
public class ObjectFoo {
	private Object foo;
	public void setFoo(Object foo) {
		this.foo = foo;
	}
	public Object getFoo() {
		return foo;
	}
}

由于Java中所有定义的类别,都以Object为最上层的父类别,所以用它来实现泛型(Generics)功能是一个不错的考虑,大部份的人都这么作,您只要撰写这么一个类别,然后可以如下的使用它:

ObjectFoo foo1 = new ObjectFoo();
ObjectFoo foo2 = new ObjectFoo();

foo1.setFoo(new Boolean(true));
// 记得转换接口
Boolean b = (Boolean) foo1.getFoo();

// 记得转换接口
foo2.setFoo(new Integer(10));
Integer i = (Integer) foo2.getFoo();

看来还不错,但是由于传回的是Object,您必须转换它的接口,问题出在这边,粗心的程序设计人员往往会忘了要作这个动作,或者是转换接口时用错了型态(像是该用Boolean却用了Integer),例如:

ObjectFoo foo1 = new ObjectFoo();
foo1.setFoo(new Boolean(true));
String s = (String) foo1.getFoo();

要命的是,语法上是可以的,所以编译器检查不出错误,真正的错误要在执行时期才会发生,这时恼人的ClassCastException就会出来搞怪,在使用Object设计泛型程序时,程序人员要再细心一些、小心一些。