泛型
泛型类和泛型方法有参数类型,这使得它们可以准确地描述用特定实例化时会发生什么。
在有泛型类之前,程序员必须使用Object编写适用于多种类型的代码。这烦琐且不安全。
泛型程序设计意味着编写的代码可以对多种不同类型的对象重用。
在Java 5中增加泛型类之前,泛型程序设计是用继承实现的。
如果用一个明确的类型而不是var声明一个变量,则可以通过“菱形”语法省略构造器中的类型参数:
ArrayList<String> files = new ArrayList<>();
省略的类型可以从变量的类型推断得出。
// Java 9扩展了菱形语法的使用范围,原先不接受这种语法的地方现在也可以使用。
// 例如,现在可以对匿名子类使用菱形语法:
ArrayList<String> passwords = new ArrayList<>(){ // diamond OK in java 9
public String get(int n){
return super.get(n).replaceAll(".", "*");
}
}
泛型类就是有一个或多个类型变量的类。public class Pair<T>{...}
泛型类可以有多个类型变量。例如,public class Pair<T, U>{...}
类型变量在整个类定义中用于指定方法的返回类型以及字段和局部变量的类型。例如,private T first;
常见的做法是类型变量使用大写字母,并且很简短
Java库使用变量E表示集合的元素类型,K和V分别表示表的键和值的类型。
T(必要时还可以用相邻的字母U和S)表示“任意类型”
除了定义泛型类,还可以定义一个带有类型参数的方法。
class ArrayAlg{
public static <T> T getMiddle(T... a){ // 这个方法是在普通类中定义的,而不是在泛型类中。不过,这是一个泛型方法,可以从尖括号和类型变量看出这点。
// 类型变量放在修饰符(public static)的后面,并在返回类型的前面。
return a[a.length / 2];
}
}
泛型方法可以在普通类中定义,也可以在泛型类中定义
当调用一个泛型方法时,可以把具体类型包围在尖括号中,放在方法名前面:
// 大多数情况下,可以省略<String>类型参数。编译器自己通过参数的类型与泛型T进行匹配推断出你想要的方法
String middle = ArrayAlg.<String>getMiddle("John", "Q.", "Public");
// 所以,可以简单地调用
String middle = ArrayAlg.getMiddle("John", "Q.", "Public");
// 几乎所有情况下,泛型方法的类型推导都是正常的。但偶尔编译器也会提示错误,如下:
double middle = ArrayAlg。getMiddle(3.14, 1729, 0);
// 因为编译器把参数自动装箱为1个Double对象和2个Integer对象,找它们的共同超类的时候,找到2个超类:Number和Comparable接口,Coparable接口本身也是一个泛型类型。
// 补救措施就是将所有参数写成double值。
如果想知道编译器对一个泛型方法调用最终推断出哪种类型,可以故意引入一个错误。然后看错误信息的提示可以将结果赋给哪些。