Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java varargs和重载的bug?_Java_Overloading_Variadic Functions - Fatal编程技术网

Java varargs和重载的bug?

Java varargs和重载的bug?,java,overloading,variadic-functions,Java,Overloading,Variadic Functions,Java varargs实现中似乎有一个bug。当一个方法被不同类型的vararg参数重载时,Java无法区分合适的类型 它给了我一个错误的方法。。。对于类型不明确 考虑以下代码: public class Test { public static void main(String[] args) throws Throwable { doit(new int[]{1, 2}); // <- no problem doit(new doubl

Java varargs实现中似乎有一个bug。当一个方法被不同类型的vararg参数重载时,Java无法区分合适的类型

它给了我一个错误的方法。。。对于类型不明确

考虑以下代码:

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);
可能是打电话给doItint…,或doItdouble。。。。在后一种情况下,整数文本将提升为双值

我很确定Java规范说这是一个模棱两可的构造,编译器只是遵循规范中规定的规则。我必须进一步研究以确定这一点

编辑-JLS的相关部分是,但这让我头疼

我认为原因是void doItint[]没有比void doItdouble[]更具体,反之亦然,因为int[]不是double[]的子类型,反之亦然。由于这两个重载同样特定,因此调用是不明确的

doIt(1, 2);
相比之下,void doItAgainint比void doItAgaindouble更具体,因为根据JLS,int是double的一个子类型。因此,对doItAgain42的调用并不含糊。

编辑2-@finnw是对的,这是一个bug。考虑这一部分的152.2.5编辑删除不适用的情况:

一个名为m的变量arity成员方法比另一个同名的变量arity成员方法更具体,如果:


一个成员方法有n个参数,另一个有k个参数,其中n≥ K第一个成员方法的参数类型为T1,Tn-1,Tn[],其他方法的参数类型为U1,Uk-1,Uk[]。让Si=Ui,1关于这一点有一个讨论

没有真正的决心,只有辞职

Varargs和auto-boxing,这也会导致难以遵循的行为,特别是与Varargs的结合,在Java的后期已经被固定在了一起,这就是它所展示的一个领域。因此,它更多的是规范中的bug,而不是编译器中的bug


至少,这是一个很好的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);
      }
   }

也许他们在谈论编写编译器的程序员。什么版本和编译器?Eclipse或JDK?FWIW,Eclipse给出了相同的错误。通过这种推理,doItint和doItdouble在没有varargs的情况下也应该是不明确的。正是与varargs的交互使得这个不明确,IIRC。实际上,您有两个级别的升级,一个是将参数序列升级为数组,另一个是将整型文字升级为双精度。我认为这是一个错误,即编译器行为与JLS不一致。如果我正确理解JLS的这一部分,那么请执行以下操作。。。应该严格地比doItdouble更具体。。。因为int是double的适当子类型。诚然,int[]不是double[]的子类型,但这不是要求之一,因此它不应影响重载解析。您不能使用泛型,因为这样您只有一个方法。据推测,该代码对double的作用要比对int的作用大。这一点很好。我将坚持在签名中使用包装器类型,然后::有趣的hack。它之所以有效,是因为自动装箱和升级从来不会同时应用于同一个参数,因此通过强制自动装箱,可以防止int双重升级,并且只有一个方法签名匹配。对于示例3中的浮点值,这将不起作用。事实上,它被确认为编译器错误,并且该错误现在已被修复。我猜您可以在以下位置找到有问题的错误: