Java SE7新特性之泛型实例创建时的类型推断

只要编译器从上下文中能够推断出类型参数,你就可以使用一个空的类型参数集合 (<>)代替调用一个泛型类的构造器所需要的类型参数。 这对尖括号通常叫做 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 . 

猜你喜欢

转载自jaesonchen.iteye.com/blog/2355647