2015-09-07 52 views
7

我讀到,自從Java 7以來,像在第一個語句中一樣在右側創建集合是錯誤的樣式,因爲編譯器可以從左側推斷出類型。爲什麼類型沒有被推斷,當離開泛型運算符

List<Integer> myList = new ArrayList<Integer>(); 

我的問題是初始化列表這樣的情況下,編譯器未找到的類型和我得到一個未經檢查的類型警告:

List<Integer> myList = new ArrayList(); 

回答

12

編譯器不推斷的類型,因爲你實例化一個原料ArrayList。但它足夠聰明,可以警告您在使用此(原始)對象時可能會出現問題。

值得一提的是這個警告背後的原因。由於type erasure,關於List的參數信息(<Integer>)將在運行時完全消失,此時變量將保存類型爲Object的元素。考慮這個片段:

List rawList = new ArrayList(); //raw list 
rawList.add(new String("hello")); 
rawList.add(new Double(12.3d)); 
List<Integer> intList = rawList; // warning! 

這段代碼會編譯,但會產生很少的警告。有一個原始列表(rawList),您可以添加任何非原始類型的列表,包括String,Double,等等。但是,當將此集合分配到列表中,該列表被指定爲只包含整數時,則這是問題。在運行時,當您試圖從intList中獲取某個元素時,您會得到ClassCastException,該元素應該是Integer,但實際上是String或其他東西。

長話短說 - 不要混合原始類型與泛型!

在你的情況下,編譯將可能人推斷的類型,如果你已經使用了鑽石:

List<Integer> list = new ArrayList<>(); //¯\_(ツ)_/¯ 
            ↑↑ 
9

因爲你已經忘記了尖括號(稱爲鑽石運營商)。

List<Integer> myList = new ArrayList<>(); 

這是語法上等同於

List<Integer> myList = new ArrayList<Integer>(); 

但不同於

List<Integer> myList = new ArrayList(); 

在你說的是,右側是一個原始類型含義ArrayList中可以容納每個對象的第3 (不僅是整數)。泛型只是編譯時間,並被編譯爲保存類型轉換。

+0

爲什麼這給編譯器更多的信息比列表 myList = new ArrayList(),因爲在左邊的通用信息可用 – PKuhn

+0

因爲兩者在語義上是不同的。在鑽石中省略這種類型只是句法上的含義。 – lschuetze

2

您可以使用鑽石操作符推斷聲明類型爲JLS (§15.9)規定。

一個類的實例創建表達式指定一個類被實例化,接着可能類型參數(§4.5.1)或金剛石(「<>」)如果被實例化的類是通用的(§8.1.2 ),然後是構造函數的實際值參數列表(可能爲空)。

List<Integer> myList = new ArrayList<>();