簡體   English   中英

錯誤與varargs和重載?

[英]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[]的子類型(反之亦然)。 由於這兩個重載是同樣特定的,因此調用是模棱兩可的。

\n

相比之下, 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)中標記為“已修復”。

Sun論壇上對此進行了討論

那里沒有真正的解決辦法,只是辭職。

Varargs(以及自動裝箱,這也導致難以遵循的行為,尤其是與varargs結合使用)已在Java的生命中被追上,這是它展示的一個領域。 因此,與其說是編譯器,不如說是規范中的錯誤。

至少,這為SCJP技巧提出了好(?)技巧問題。

有趣。 幸運的是,有兩種方法可以避免此問題:

您可以在方法簽名中使用包裝器類型:

   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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM