[英]bug with varargs and overloading?
Java varargs實現中似乎存在一個錯誤。 當方法使用不同類型的vararg參數重載時,Java無法區分適當的類型。
它給我一個錯誤The method ... is ambiguous for the type ...
考慮以下代碼:
public class Test
{
public static void main(String[] args) throws Throwable
{
doit(new int[]{1, 2}); // <- no problem
doit(new double[]{1.2, 2.2}); // <- no problem
doit(1.2f, 2.2f); // <- no problem
doit(1.2d, 2.2d); // <- no problem
doit(1, 2); // <- The method doit(double[]) is ambiguous for the type Test
}
public static void doit(double... ds)
{
System.out.println("doubles");
}
public static void doit(int... is)
{
System.out.println("ints");
}
}
文檔說:“通常來說,您不應該重載varargs方法,否則程序員將很難弄清楚調用哪個重載。”
但是,他們沒有提到此錯誤,發現困難的不是程序員,而是編譯器。
有什么想法嗎?
編輯 -編譯器:Sun JDK 1.6.0 U18
問題在於它是模棱兩可的。
doIt(1, 2);
可以是對doIt(int ...)
或doIt(double ...)
的調用。 在后一種情況下,整數文字將提升為double
值。
我非常確定Java規范說這是一個模棱兩可的構造,並且編譯器僅遵循該規范規定的規則。 (我必須對此進行進一步研究才能確定。)
編輯 -JLS的相關部分是“ 15.12.2.5選擇最具體的方法 ”,但這使我很頭疼 。
我認為推理的原因是
void doIt(int[])
不比
void doIt(double[])
更具體(反之亦然
void doIt(double[])
因為
int[]
不是
double[]
的子類型(反之亦然)。
由於這兩個重載是同樣特定的,因此調用是模棱兩可的。
相比之下,
void doItAgain(int)
是大於特定
void doItAgain(double)
因為
int
是的子類型
double
根據JLS中。
因此,對
doItAgain(42)
的調用並不明確。
編輯2- @finnw是正確的,這是一個錯誤。 考慮15.12.2.5的這一部分(已編輯以刪除不適用的案例):
在以下情況下,一個名為m的可變arity成員方法比具有相同名稱的另一可變arity成員方法更具體 :
一種成員方法具有n個參數,另一種成員具有k個參數,其中n≥k。 第一種成員方法的參數類型為T1,...。 。 。 ,Tn-1,Tn [],另一種方法的參數類型為U1,。 。 。 ,Uk-1,Uk []。 令Si = Ui,1 <= i <= k。 然后:
- 對於從1到k-1的所有j,Tj <:Sj,並且
- 對於從k到n的所有j,Tj <:Sk
將其應用於n = k = 1的情況,我們看到doIt(int[])
比doIt(double[])
更具體。
實際上,有一個錯誤報告
,Sun承認確實是一個錯誤,盡管他們將其優先級設置為“非常低”
。 該錯誤現在在Java 7(b123)中標記為“已修復”。
有趣。 幸運的是,有兩種方法可以避免此問題:
您可以在方法簽名中使用包裝器類型:
public static void doit(Double... ds) {
for(Double currD : ds) {
System.out.println(currD);
}
}
public static void doit(Integer... is) {
for(Integer currI : is) {
System.out.println(currI);
}
}
或者,您可以使用泛型:
public static <T> void doit(T... ts) {
for(T currT : ts) {
System.out.println(currT);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.