2008-11-20 53 views
227

我在導航Java規則中推斷泛型類型參數時遇到了一些問題。考慮下面的類,它有一個可選的list參數:Collections.emptyList()返回一個列表<Object>?

import java.util.Collections; 
import java.util.List; 

public class Person { 
    private String name; 
    private List<String> nicknames; 

    public Person(String name) { 
    this(name,Collections.emptyList()); 
    } 

    public Person(String name,List<String> nicknames) { 
    this.name = name; 
    this.nicknames = nicknames; 
    } 
} 

我的Java編譯器提供了以下錯誤:

Person.java:9: The constructor Person(String, List<Object>) is undefined 

Collections.emptyList()返回類型爲<T> List<T>,不List<Object>。添加投不利於

public Person(String name) { 
    this(name,(List<String>)Collections.emptyList()); 
} 

產生

Person.java:9: inconvertible types 

使用EMPTY_LIST代替emptyList()

public Person(String name) { 
    this(name,Collections.EMPTY_LIST); 
} 

產量

Person.java:9: warning: [unchecked] unchecked conversion 

而下面的變化麥ES錯誤消失:

public Person(String name) { 
    this.name = name; 
    this.nicknames = Collections.emptyList(); 
} 

誰能解釋什麼類型的檢查規則,我對這裏跑了,最好的辦法來解決呢?在這個例子中,最終的代碼示例是令人滿意的,但是對於更大的類,我希望能夠在這個「可選參數」模式下編寫方法,而不需要重複代碼。

額外贈金:何時適合使用EMPTY_LIST而不是emptyList()

+1

對於所有Java泛型相關問題,我強烈推薦Maurice Naftalin,Philip Wadler撰寫的「[Java泛型和集合](http://oreilly.com/catalog/9780596527754/)」。 – 2008-11-20 20:39:24

回答

389

你遇到的問題是,即使方法emptyList()返回List<T>,你沒有提供它的類型,所以它默認返回List<Object>。您可以提供的類型參數,並讓您的代碼像預期的那樣,這樣的:

public Person(String name) { 
    this(name,Collections.<String>emptyList()); 
} 

現在,當你在做直轉讓,編譯器可以計算出泛型類型參數爲您服務。這就是所謂的類型推斷。例如,如果你這樣做:

public Person(String name) { 
    List<String> emptyList = Collections.emptyList(); 
    this(name, emptyList); 
} 

那麼emptyList()通話將正確返回一個List<String>

+10

明白了。從ML世界來看,Java對於我無法推斷出正確的類型很奇怪:形式參數的類型和emptyList的返回類型顯然是可以統一的。但我猜這個類型推理器只能採用「嬰兒步驟」。 – 2008-11-20 20:43:28

85

你想使用:

Collections.<String>emptyList(); 

如果你看一下源什麼的emptyList做你看,它實際上只是做了

return (List<T>)EMPTY_LIST; 
26

的的emptyList方法有此簽名:

public static final <T> List<T> emptyList() 

<T>之前的單詞列表表示它推斷出g通用參數T來自結果分配給的變量類型。因此,在這種情況下:

List<String> stringList = Collections.emptyList(); 

的返回值,然後通過List<String>類型的變量明確提到,所以編譯器可以計算出來。在這種情況下:

setList(Collections.emptyList()); 

有沒有明確的返回變量的編譯器使用弄清楚泛型類型,所以它默認爲Object