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
.