2024年4月19日发(作者:)
浅谈Java泛型编程
原文地址:/?messageID=154504
我原本想全文翻译Generics in the Java Programming Language,但是功力不够,太耗时
间。于是乎按照原文的框架,翻了一些再加上自己写的一点东西。
第一次写文,如有谬误还清指出~~谢谢!
浅谈Java泛型编程
1 引言
在JDK 1.5中,几个新的特征被引入Java语言。其中之一就是泛型(generics)。
泛型(generics,genericity)又称为“参数类型化(parameterized type)”或“模板
(templates)”,是和继承(inheritance)不同而互补的一种组件复用机制。
继承和泛型的不同之处在于——在一个系统中,继承层次是垂直方向,从抽象到具体,而泛型是水
平方向上的。当运用继承,不同的类型将拥有相同的接口,并获得了多态性;当运用泛型,将拥有
许多不同的类型,并得以相同的算法作用在它们身上。因此,一般说来,当类型与实现方法无关
时,使用泛型;否则,用继承。
泛型技术最直接联想到的用途就是建立容器类型。下面是一个没有使用泛型技术的例子:
List myIntList = new LinkedList();// 1
(new Integer(0));// 2
Integer x = (Integer)or().next();// 3
显然,程序员知道究竟是什么具体类型被放进了myIntList中。但是,第3行的类型转换
(cast)是必不可少的。因为编译器仅仅能保证iterator返回的是Object类型。要想保证将这个
值传给一个Integer类型变量是安全的,就必须类型转换。
除了使代码显得有些混乱外,类型转换更带来了运行时错误的可能性。因为程序员难免会犯错误。
使用了泛型技术,程序员就可以确切地表达他们的意图,并且把myIntList限制为包含一种具体
类型。下面就是前一个例子采用了泛型的代码段:
List
(new Integer(0));// 2
Integer x = or().next();// 3
List
有类型参数的泛型接口,在这里就是指Integer。
现在,我们在第1行里使用Integer作为类型参数,而不是在第3行里做类型转换。这样,在编
译时刻,编译器就能够检查程序的正确性——无论何时何地,编译器都将保证myIntList的正确
使用。相反地,类型转换仅仅告诉我们——在这里,程序员认为这样做是对的。
采用泛型可以增强代码可读性和健壮性(robustness)。
2 定义泛型
public interface List
void add(E x);
Iterator
}
public interface Interator
E next();
boolean hasNext();
}
这是一段Collection里代码,一个完整的泛型定义。尖括号里的E就是形式类型参数(formal
type parameters)。在泛型定义中,类型参数的用法就像一般具体类型那样。
在引言中,我们看到初始化了一个泛型List——List
型参数(actual type argument)Integer。
你可以想象List
public interface List {
void add(Integer x);
Iterator< Integer > iterator();
}
和C++中对模板的处理有很大的不同,这里没有第2份副本。Java采用的是拭去法(erasure)
而C++采用的是膨胀法(expansion)。一个泛型定义只被编译一次,只生成一个文件,就像一
般的class和interface一样。
形式类型参数可以不止1个,如:
class Bar < E, D> { …… }
3 通配符
3.1 泛型和子类
下面的这段代码合法么?
List
List
假设这两行代码是正确的,那么下面的操作:
(new Object());// 3
String str = (0);// 4
将导致运行时刻错误。通过别名lo存取ls时,我们可以插入任意类型的对象——ls就不再仅仅持
有String了。
Java编译器消除了这种错误发生的可能性。第2行将导致编译时刻错误。
一般地说,如果Foo是Bar的子类,G定义为某种泛型,那么G
3.2 通配符
如果,我们试图使用泛型的方法编写一个打印Collection内所有元素的函数,要怎么做?
void printCollection (Collection
for (Objcet obj : c) {// jdk 1.5中新增的语法,见5.1
n(obj);
}
}
显然这样是不行的,因为通过3.1我们可以知道——Collection
的父类。
那么,所有Collection的父类是什么?Collection>——未知类型的Collection(collection
of unknown),一个元素可以匹配为任意类型的Collection。“?”被称作通配类型。上述的代
码,可以改写成这样:
void printCollection(Collection> c) {
for (Object obj : c) {
n(obj);
}
}
现在,我们可以使用任意类型的Collection作为参数了。注意,在printCollection内,用
Objcet类型访问c的元素是安全的,因为任何一种具体类型都是Object的子类。
但是这样的操作是错误的:
List> list = new ArrayList
(…);// compile-time error!
因为list被定义为List>,“?”指代了一个未知类型。(…)无法保证插入的对象类型就是
发布评论