2011-08-28 66 views
13

如果我有一個類Foo一般推論在構造

public class Foo<T> { 
    public Foo(T t) { 
     //do something 
    } 

    public static <E> void bar(E e) { 
     //do something 
    } 
} 

爲什麼Foo.bar("String");推斷E是一個String(因此不會拋出一個編譯器警告),但new Foo("String");不能推斷T是一個字符串?

+1

你看到的確切錯誤是什麼? – linuxuser27

+0

@ linuxuser27你在'new Foo(「String」)上得到一個原始類型警告;' – Jeffrey

回答

10

因爲構造函數可以被認爲是一種特殊的實例方法,所以它不是鍵入的 - 它從類名(帶有類型參數)中獲取類型,例如Foo<String>。即構造函數沒有被定義爲:

public <T> Foo(T t) ... 

也不可能。這樣做會隱藏泛型類的(你會得到一個警告)

靜態方法但是類型。僅供參考的通用FYI等於:

Foo.<String>bar("String"); 
+1

+1。非常有趣,但我仍然不明白爲什麼在這種情況下,它不能通過類似於參數列表的機制來推斷 – linuxuser27

+0

您是否注意到了這一點:如果您聲明您的類是這樣的:'class TestClass '和您的構造函數'公共 TestClass(T t)'你沒有得到警告,但是如果你這樣做:'TestClass '和你的構造函數'public TestClass(T t)'你得到一個編譯器警告,聲明「type參數T隱藏類型T「 –

+0

@Varun Achar您可以聲明[通用構造函數](http://download.oracle.com/javase/tutorial/java/generics/genmethods.html),並且如果在構造函數上重新聲明你確實隱藏了班級'。我相信boehemian試圖說的是,因爲我沒有創建通用構造函數,所以它從類繼承它的類型,而不是相反。但是它仍然留下了類爲什麼不能從構造函數中推斷出類型參數的問題。 – Jeffrey

1

我認爲你需要做這

new Foo<String>("String"); 

告訴得到通過的泛型信息;類似於Collections API。

+2

這是正確的。 OP沒有問'需要做什麼',而是'爲什麼',因爲在靜態方法調用中這是不需要的。 – linuxuser27

+0

什麼linuxuser說,做'新Foo (「字符串」);'似乎重複,當你已經傳遞一個字符串到構造函數。 – Jeffrey

+0

我認爲Java 7中的重複性會降低。 –

1

考慮到這一點,我將在這裏進行猜測。考慮以下幾點:

public class Foo { 
    public <E> Foo(E t) { 
     //do something 
    } 

    public static <E> void bar(E e) { 
     //do something 
    } 
} 

在上面的類,你事先沒有任何警告實例Foo時如下:

Foo f = new Foo("String"); 

這工作,因爲E類型正在這裏推斷。就像你期望它在方法情況下發生一樣。然而,你得到的錯誤並不是因爲參數類型不是被推斷出來的,而是因爲無法推斷類的原始類型。

我認爲這是歸結爲類的原始類型可以傳播到方法,但方法不能使用推理設置類的原始類型。

+0

我相信這是波希米亞人正在做的事情。由於您沒有聲明類的類型參數,所以構造函數沒有被賦予類型。 – Jeffrey

+0

@傑弗裏 - 我同意。這是一個很好的問題。謝謝。 – linuxuser27

3

當Java實現泛型時,確定了一個沒有類型參數的實例化的泛型類將始終返回一個原始類型。這與編譯器試圖推斷類型的缺少類型參數的泛型方法不同。從Java教程:

通常,Java編譯器可以推斷泛型方法調用的類型參數。因此,在大多數情況下,您不必指定它們。

但是當討論轉向構造函數:

注意採取泛型類實例化過程中利用自動類型推斷,你必須指定鑽石。

Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning

源:http://download.oracle.com/javase/tutorial/java/generics/gentypeinference.html

這仍然在下面的例子中,因爲HashMap中()構造是指HashMap原始類型,而不是Map<String, List<String>>型編譯器生成一個未檢查轉換警告在Java 7中也是如此,但他們試圖通過支持菱形語法來減少重複性。例如,Foo<String> foo = new Foo<>("String")。見this section of the same article

+0

很好的文檔。 – Jeffrey

1

@Kublai Khan的回答是正確的;爲了向後兼容,new Foo(s)的類型是生的Foo

Java7的構造函數菱形類型推斷(new Foo<>(s))與方法類型推理相同,並且在方法類型推斷上定義。

http://cr.openjdk.java.net/~darcy/ProjectCoin/ProjectCoin-Documentation-v0.9375.html#diamond

如果類實例創建表達式使用「<>」的Elid到類類型的參數,方法M1的列表... MK是爲重載和類型參數推斷的目的來定義。 ..

...然後M1之一... MK被選擇時,使用§15.12.2描述的方法(確定方法簽名)

你的懷疑是正確的,構造ç就像方法一樣使用推理,沒有本質區別。由於向後兼容性問題,您只需添加<>

爲什麼需要Java 6年才能添加此功能是另一回事。