泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后进行酱紫类型转换的代码具有更好的安全性和可读性。泛型对于集合类尤其有用,例如,ArrayList就是一个无处不在的集合类。从表面上来看,泛型很像C++中的模板。
8.1 为什么要使用泛型程序设计泛型程序设计(Generic programming)意味着编写的代码可以被很多不同类型的对象所重用。
8.1.1 类型参数的好处泛型提供了一个类型参数(type parameters),可以用来指示元素的类型
ArrayList
这样使得代码具有更好的可读性
8.2 定义简单泛型类一个泛型类(generic class)就是具有一个或多个类型变量的类,例如以下一个Pair类的代码
package chap8.pair1;public class Pair
Pair类引入了一个类型变量T,用尖括号<>括起来,并放在类名的后面。泛型类可以有多个类型变量
public class Pair
类定义中的类型变量指定方法的返回类型以及与和局部变量的类型
private T first;
用具体的类型替换类型变量就可以实例化泛型类型
Pair
class ArrayAlg{public static
这个方法是在普通类中定义的,而不是在泛型类中定义的。然而,这是一个泛型方法。注意,类型变量放在修饰符(这里是public static)的后面,返回类型的前面
泛型方法可以定义在普通类中,也可以定义在泛型类中
调用一个泛型方法是,在方法名前的前括号中放入具体的类型
String middle = ArrayAlg.
大多数情况下,可以省略
double middle = ArrayAlg.getMiddle(3.14, 1729, 0);
编译器会自动打包参数为1个Double和2个Integer对象,而后寻找这些类的共同超类型,找到Number和Comparable接口,其本身也是一个泛型类型。在这种情况下,可以采取的补救措施是将所有的参数写为double值
8.4 类型变量的限定有的时候,类或方法需要对类型变量加以约束,例如,需要类型变量实现了CompareTo方法,解决方案是将类型变量限制为实现了Comparable接口的类
class ArrayAlg{ public static
这里为什么使用extends而不是implements,毕竟Comparable是一个接口,可以理解为:
这里的T应该是绑定类型的值类型(subtype)。T和绑定类型可以是类,也可以是接口。选择关键词extends的原因是更接近子类的概念,并且Java的设计者也不打算在语言中再添加一个新的关键字(如sub)
一个类型变量或者通配符可以有多个限定,例如
T extends Comparable & Serializable
限定类型用&分隔,而逗号用来分隔类型变量
利用泛型重新编写了一个minmax,这个方法计算泛型数组的最大值和最小值,并返回Pair
pair2/PairTest2.java
package chap8.pair2;import java.time.LocalDate;public class PairTest2 { public static void main(String[] args) { LocalDate[] birthdays = { LocalDate.of(1906, 12, 9), LocalDate.of(1815, 12, 10), LocalDate.of(1903, 12, 3), LocalDate.of(1910, 6, 22), }; Pair
虚拟机没有泛型类型对象——所有对象都属于普通类
8.5.1 类型擦除无论何时定义一个泛型类型,都自动提供了一个相应的原始类型。原始类型的名字就是删除类型参数后的泛型类型名。擦除类型变量,并替换为限定类型。
8.5.2 翻译泛型表达式如果程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。
Pair
class DateInterval extends Pair
如上代码,一个日期区间是一对LocalDate对象,并且需要覆盖这个方法来确保第二个值永远不小于第一个值,擦除之后可能变为
class DateInterval extends Pair{ public void setSecond(LocalDate second) { ..、} ...}
令人奇怪的是,存在另一个从Pair继承的setSecond方法,即
public vodi setSecond(Object second)
这里希望对setSecond的调用具有多态性,编译器会生成一个桥方法(bridge method:
public void setSecond(Object second){ setSecond((Date) second); }
8.5.4 调用遗留代码设计Java泛型类型是,主要目标是允许泛型代码和遗留代码之间能够相互操作。
Dictionary
将Dictionary
slider.setLabelTable(labelTable); //Warning
在查看了警告之后,可以利用注解(annotation)使之消失,注释必须放在生成这个警告的代码所在的方法之前,如下:
@SuppressWarnings("unchecked")Dictionary