我们可以通过将"public class Box" 修改为 "public class Box<T>"而定义一个泛型,在这个定义中,使用了一个类型变量(type variable) T,而且T能够在Box类之内的任何地方被使用。这中定义的方法其实并不复杂,并且在接口(interface)中也被使用。实际上,T可以看作是一种特殊的数据类型,它的值就是我们要传递给它的参数,参数的类型可以是类,也可以是接口,或者其他类型的变量,但是却不能是原始类型(primitive)的数据。
/**
* Generic version of the Box class.
*/
public class Box<T> {
private T t; // T stands for "Type"
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
如上所示,我们用T代替了其中所有的Object。为了在我们的代码中能够使用泛型类,我们必须要用具体的类型比如Integer来代替T,这也叫做泛型调用(generic type invocation)。
实际上,泛型调用和普通的方法调用非常相似,所不同的是方法调用时传递的是参数,而泛型调用是传递的是一种具体的类型参数,比如Integer。泛型调用也叫做参数化类型(parametersized type)。
为了实例化使用泛型技术定义的类,和通常一样要使用new关键字,如下所示:
integerBox = new Box<Integer>();
或者如果写的更加全面的话可以用下面的语句:
Box<Integer> integerBox = new Box<Integer>();
一旦integerBox被实例话了,我们就可以使用它的get方法而无需进行参数的转换。而且如果试图想加一个类型不符的参数到box,编译器就会报错。
我们一定要记住,类型变量并不是真正的数据类型本身,上面的例子中,在文件中是找不到T.java或者T.class的,而且T也不是类名Box的一部分。实际上在编译的时候,所有和泛型有关的信息都会被去掉,从而最后只有Box.class文件,这会在后面进一步讨论。
另外还要注意的是泛型可以多个类型参数,但是每个类型参数在所定义的类或者接口中不能重复。例如Box<T, T>则是有问题的,而Box<T, U>则是可以使用的。
按照惯例,类型参数一般使用单个大写的字母表示。这样就可以普通变量的命名形成了明显的对比。如果不按照此惯例,就很难区分类型参数名和普通的类名或者接口名。
通常使用的类型参数如下:
E - 元素(Element);
K - 关键字(Key);
N - 数(Number);
T - 类型(Type);
V - 值(Value);
S,U,V等 - 第2个,第3个,第4个类型。
文章评论(0条评论)
登录后参与讨论