繁体   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