只要编译器从上下文中能够推断出类型参数,你就可以使用一个空的类型参数集合(<>
)代替调用一个泛型类的构造器所需要的类型参数。 这对尖括号通常叫做diamond.
举个例子, 考虑下面的变量声明:
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
在Java SE 7中, 你可以使用一个空的类型参数集合(<>
)代替构造器的参数化类型:
Map<String, List<String>> myMap = new HashMap<>();
注意:想要在泛型类初始化期间利用自动类型推断,你必须要指定 diamond。下面的例子中,由于HashMap()
构造器引用的是HashMap
原始类型而不是Map<String, List<String>>
类型,编译器会产生一个未检查的转换警告:
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<>());
注意: diamond通常在方法调用中起作用;然而, 在变量声明时建议首要使用diamond。
相比之下, 下面的例子可以编译通过:
// 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>
指定Integer
类型作为形式参数X
。注意, 这个泛型类的构造器包含一个形式参数。编译器推断这个泛型类的构造器的形式参数T的类型为String
(因为这个构造器的实际参数是一个String
对象)。
在Java SE 7之前,和泛型方法一样,编译器能够推断泛型构造器的实际参数。然而在Java SE 7中,如果你使用diamond (<>
),编译器能够推断被实例化的泛型类的实际参数 。考虑下面的例子,在Java SE 7以及之后的版本中都有效:
MyClass<Integer> myObject = new MyClass<>("");
在这个例子中,编译器推断泛型类MyClass<X>
的形式参数X
的类型为Integer
。 并且推断这个泛型类的构造器的形式参数T的类型为String
.
本文翻译自Oracle官方文档http://docs.oracle.com/javase/7/docs/technotes/guides/language/type-inference-generic-instance-creation.html,如有不正确的地方,敬请指正,谢谢!