我剛纔看到this C# question,想知道如果在Java中會發生類似的情況。它可以與在Java中調用含糊不清的重載構造函數
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
通話
new A<Integer>(43);
是模糊的,我看不出有什麼辦法如何解決它。有沒有?
我剛纔看到this C# question,想知道如果在Java中會發生類似的情況。它可以與在Java中調用含糊不清的重載構造函數
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
通話
new A<Integer>(43);
是模糊的,我看不出有什麼辦法如何解決它。有沒有?
是,參數化類型JLS3#4.5.2的成員可能會在正常類聲明(#8.4.8)中排除的衝突中結束。想出很多這種例子很容易。
而在Java中,由於T
和Integer
之間沒有子類型關係,所以在您的示例中,兩個構造函數都沒有比另一個更具體。另請參閱Reference is ambiguous with generics
如果方法重載創建了這種模糊性,我們通常可以選擇使用不同的方法名稱。但構造函數不能被重命名。
更多的詭辯:
如果<T extends Integer>
,那麼確實T
是Integer
一個亞型,那麼第二個構造函數是比第一一個更具體,而第二人會選擇。
其實javac不會允許這兩個構造函數共存。目前的Java語言規範中沒有任何東西禁止它們,但字節碼中的限制迫使javac禁止它們。看到Type Erasure and Overloading in Java: Why does this work?
另外一點:如果<T extends Integer>
,因爲Integer
是final
,T只能是Integer
,所以Integer
也必須是T
一個亞型,因此不是第二構造也比第一次更具體?
第final
沒有考慮子類型關係。實際上,有一天可以從Integer
中刪除final
,Java甚至指定刪除final
不會破壞二進制兼容性。
這表明清楚,並更多的感謝鏈接。 – maaartinus 2011-04-17 18:24:19
事實上,它是不明確的,所以如果你嘗試new A<Integer>(new Integer(0))
,也不會編譯。
您可以在施工期間下降仿製藥(並抑制警告):
A<Integer> a = new A(42);
或較少優選使用反射(如你又不得不抑制警告)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
看看'Builder Design Pattern','Factory Pattern'或者類似的東西。使用上面提到的構造函數會以'A a = new A(42);'這樣的語句結束,它不會告訴任何關於'42'實際是什麼的東西。有關軟件設計的更清晰的方法是'A a = A.createWithCapacity(42);'。此外,這解決了你的歧義。 –
2012-09-26 08:21:02
@ coding.mof:我使用這些模式很多,但最後他們不得不調用構造函數。然而,這可以很容易地解決,例如,由一個虛構的構造器參數,因爲沒有人關心它的樣子。我真的不記得我想要什麼;也許我只是好奇。 – maaartinus 2012-09-26 09:02:01