泛型是参数化类型,在定义类、接口或方法时的数据类型可以为泛型,含义为适应多种数据类型,在创建对象时确定具体的类型。
泛型的声明
Java中声明泛型的符号为“<>”,通常在尖括号中使用单一大写字母代表泛型符号。在JDK的类中习惯采用字母“E”,但这不是强制规定,可以采用符合Java标识符规定的任何字符串。下面的叙述中统一采用“E”定义泛型符号。
声明泛型类
声明泛型类的语法为:
[类修饰符] class 类名 [extends 父类名] [implements 接口列表] {
// 类体
}
带有泛型参数的类处理的某一个数据项是泛型数据,表明适应多种数据类型。标识符“E”作为类型说明符会出现在类体中,这就是说在类中实现该数据项运算是应该满足不同可能的具体数据类型。
如果一个类中有多个数据为泛型,需要在尖括号中以列表的方式给出,例如写为“”则代表有两个数据是泛型。
声明泛型接口
声明泛型接口的语法为:
[public] interface 接口名 [extends 父接口列表] {
// 接口体
}
在接口中声明的成员方法的调用参数类型和返回值参数类型说明中会使用标识符E作为其类型说明。
泛型方法
一个泛型类中的方法的参数类型说明和返回值类型说明可以采用泛型,例如在一个采用标识符E声明的泛型类中的一个方法声明为:
public E get(E[] v, int index) {
// 方法体
return (E) x;
}
以上声明的get()方法有两个形式参数,第一个为泛型数组,返回值为同样类型的泛型,return语句中返回值(E)x表明返回结果前需要做强制类型转换,这当然需要在方法中保证强制类型转换是可行的。
泛型的使用
如果一个类是泛型的,在创建这个类的对象时要用具体的类型替代泛型标识符。
public class RingFiFo {
// …
public RingFiFo(int len) {
// …
}
}
上面的代码框架定义了一个泛型类,其中有一个构造方法。创建这个类的对象的语句可以写为:
RingFiFo x = new RingFiFo(100);
创建对象时使用String类型具体化泛型,在通过对象x引用类的成员时,成员中的泛型标识符E被具体化为String。
泛型在具体化时不能采用基础数据类型,即boolean、char、byte、short、int、long、float和double类型。如果需要具体化为基础数据类型,必须使用基础数据类型对应的包装类,即采用Boolean、Character、Byte、Short、Integer、Long、Float和Double类依次对应上面的8种类型。
由于泛型可能代表所有类型(实际上一个具体的Java泛型可以某一部分有继承关系的类型),在泛型类的内部声明一个泛型对象时就只能声明为Object类型(语法上为任意类型),这样带来的问题是泛型对象的处理受到很大限制。
实现一个泛型环形队列
队列是先入先出的数据结构,为了存储方便,同时又考虑到效率问题,在存储上应该设计为环形结构。如果要求其存储的数据对象可以是任意类型,就必须设计为泛型参数。
队列固定长度为n,采用两个整型变量存储队列的单元序号,head是首单元序号,tail是尾单元序号,设定head指向队列头之前的一个单元,tail指向队列尾单元。全部“空”单元值为null。
初始状态head和tail为0,当head和tail的值相等时,如果指向单元为null表示队列为空状态,如果指向单元为非null表示队列为满状态。
设计两个方法实现数据加入队列和从队列取出。
方法
说明
booleanput(Ee)
向对列队尾部添加成员e。如果队列为非满状态,添加成功同时返回true,如果队列为满状态,添加失败同时返回false
Eget()
从队列头部取出一个成员,队列非空返回成员,队列空返回null
将队列的存储单元首尾相接,构成一个环形存储结构,如图。
行号
例8-1,泛型环形队列RingFiFo类完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class RingFiFo {
private final Object[] element;
private int head, tail;
public RingFiFo(int len) {
element = new Object[len];
for(Object x : element) x = (E)null;
head = 0;
tail = 0;
}
E get() {
if((head==tail) & (element[head]==null))
return null;
int iget = (head+1)%element.length;
Object result = element[iget];
element[iget] = null;
head = iget;
return (E)result;
}
boolean put(E e) {
if((head==tail) & (element[head]!=null))
return false;
tail = (tail+1)%element.length;
element[tail] = e;
return true;
}
public static void main(String[] args) {
String str[] = {"北京","上海","大连","天津","西安"}, x;
RingFiFo rff = new RingFiFo<> (4);
for(String s : str) {
if(rff.put(s)) System.out.println("添加(" + s + ")成功");
else System.out.println("添加(" + s + ")失败");
}
for(int n=0; n<5; n++) {
if((x=rff.get())!=null) System.out.println("取出(" + x + ")");
else System.out.println("取出失败");
}
}
}