2011-04-17 125 views
2

我剛纔看到this C# question,想知道如果在Java中會發生類似的情況。它可以與在Java中調用含糊不清的重載構造函數

class A<T> { 
    A(Integer o) {...} 
    A(T o) {...} 
} 

通話

new A<Integer>(43); 

是模糊的,我看不出有什麼辦法如何解決它。有沒有?

+0

看看'Builder Design Pattern','Factory Pattern'或者類似的東西。使用上面提到的構造函數會以'A a = new A(42);'這樣的語句結束,它不會告訴任何關於'42'實際是什麼的東西。有關軟件設計的更清晰的方法是'A a = A.createWithCapacity(42);'。此外,這解決了你的歧義。 – 2012-09-26 08:21:02

+0

@ coding.mof:我使用這些模式很多,但最後他們不得不調用構造函數。然而,這可以很容易地解決,例如,由一個虛構的構造器參數,因爲沒有人關心它的樣子。我真的不記得我想要什麼;也許我只是好奇。 – maaartinus 2012-09-26 09:02:01

回答

2

是,參數化類型JLS3#4.5.2的成員可能會在正常類聲明(#8.4.8)中排除的衝突中結束。想出很多這種例子很容易。

而在Java中,由於TInteger之間沒有子類型關係,所以在您的示例中,兩個構造函數都沒有比另一個更具體。另請參閱Reference is ambiguous with generics

如果方法重載創建了這種模糊性,我們通常可以選擇使用不同的方法名稱。但構造函數不能被重命名。


更多的詭辯:

如果<T extends Integer>,那麼確實TInteger一個亞型,那麼第二個構造函數是比第一一個更具體,而第二人會選擇。

其實javac不會允許這兩個構造函數共存。目前的Java語言規範中沒有任何東西禁止它們,但字節碼中的限制迫使javac禁止它們。看到Type Erasure and Overloading in Java: Why does this work?

另外一點:如果<T extends Integer>,因爲Integerfinal,T只能是Integer,所以Integer也必須是T一個亞型,因此不是第二構造也比第一次更具體?

final沒有考慮子類型關係。實際上,有一天可以從Integer中刪除final,Java甚至指定刪除final不會破壞二進制兼容性。

+0

這表明清楚,並更多的感謝鏈接。 – maaartinus 2011-04-17 18:24:19

2

事實上,它是不明確的,所以如果你嘗試new A<Integer>(new Integer(0)),也不會編譯。

3

您可以在施工期間下降仿製藥(並抑制警告):

A<Integer> a = new A(42); 

或較少優選使用反射(如你又不得不抑制警告)

Constructor<A> c = A.class.getDeclaredConstructor(Integer.class); 
A<Integer> a = c.newInstance(42);