泛型实例创建的类型推断
首先这是Java SE 7引入的新特性。
可以把调用泛型类构造器要求的类型参数替换为一个空类型参数(<>)只要编译器能够从上下文中推断出类型参数。这对空三角括弧被不正式的称为“钻石”。(因为它的形状确实像钻石!)
例如考虑下面的变量声明:
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
在Java SE 7 中你可以把构造器的参数化的类型替换为一对空的尖括弧(<>):
Map<String, List<String>> myMap = new HashMap<>();
注意为了在泛型类实例化时充分利用自动类型推断功能,你必须指定钻石(<>)。在下面的例子中,编译器产生了一个未检查的转换警告因为HashMap()构造器引用了HashMap原始类型而不是Map
Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning
Java SE 7支持有限的泛型实例创建类型推断;你只能在构造器的参数化的类型在上下文中很明显时使用类型推断。例如下面的例子不能成功编译:
List<String> list = new ArrayList<>();
list.add("A");
// The following statement should fail since addAll expects
// Collection<? extends String>
list.addAll(new ArrayList<>());
注意钻石经常和方法调用一起使用;然而建议你主要在声明变量的时候使用钻石。
作为比较下面的例子编译成功:
// The following statements compile:
List<? extends String> list2 = new ArrayList<>();
list.addAll(list2);
类型推断和泛型类、非泛型类的泛型构造器
注意泛型类和非泛型类的构造器都可以是泛型的(换句话说,声明他们自己的形式类型参数)
考虑下面的例子:
class MyClass<X> {
<T> MyClass(T t) {
// ...
}
}
考虑下面的MyClass类实例化,在Java SE 7以及之前都是正确的:
new MyClass<Integer>("")
这个语句创建了一个参数化类型类MyClass的实例;这条语句明确的指定了用类型Integer代替泛型类MyClass的形式参数X,注意到这个泛型类的构造器包含了形式类型参数T。编译器推断这个泛型类的构造器的形式类型参数T因该是String (因为这个构造器的实际参数是String类型的对象)。
从发布到Java SE 7编译器都能推断泛型构造器实际的类型参数,类似于泛型方法。然而,Java SE 7的编译器可以推断出泛型类被实例化的实际类型参数如果你使用钻石(<>)。考虑下面的例子,在Java SE 7往后都是正确的:
MyClass<Integer> myObject = new MyClass<>("");
在这个例子中,编译器推断Integer为泛型类MyClass的形式类型参数X,也推断出类型String为这个泛型类的构造器的形式类型参数T。