varargs和重载的错误?

pst*_*ton 21 java overloading variadic-functions

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

文件说:"一般来说,你不应该重载可变参数的方法,或将难以程序员找出哪些超载被调用."

但是他们并没有提到这个错误,并不是程序员发现它很困难,而是编译器.

想法?

编辑 - 编译器:Sun jdk 1.6.0 u18

Ste*_*n C 13

问题是,它不明确的.

doIt(1, 2);
Run Code Online (Sandbox Code Playgroud)

可能是一个电话doIt(int ...),或doIt(double ...).在后一种情况下,整数文字将被提升为double值.

我很确定Java规范说这是一个模糊的构造,编译器只是遵循规范规定的规则.(我必须进一步研究这个以确定.)

编辑 - JLS的相关部分是" 15.12.2.5选择最具体的方法 ",但这让我头疼.

我认为推理将void doIt(int[])不是更具体(反之亦然),而不是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,英国[].设Si = Ui,1 <= i <= k.然后:

  • 对于从1到k-1的所有j,Tj <:Sj,和,
  • 对于从k到n的所有j,Tj <:Sk

将此应用于n = k = 1的情况,我们看到它doIt(int[])更具体doIt(double[]).


事实上,有一个bug报告和Sun承认,这的确是一个错误,虽然他们已经优先为"非常低".该错误现在在Java 7(b123)中标记为已修复.

  • 通过这种推理,doIt(int)和doIt(double)也应该是模糊的(没有varargs). (3认同)
  • 与varargs的互动使得这个模糊的IIRC.实际上你有两个级别的升级,1)将一系列args升级为数组,以及2)将积分文字提升为双精度. (2认同)
  • 我认为这是一个错误(即编译器行为与JLS不一致.)如果我正确理解JLS的那一部分那么`doIt(int ...)`应该比`doIt严格更具体(double .. .)`因为`int`是`double`的正确子类型.确实`int []`不是`double []`的子类型,但这不是要求之一,所以它不应该影响重载决策. (2认同)

Thi*_*ilo 7

在Sun论坛上讨论了这个问题.

那里没有真正的解决方案,只是辞职.

Varargs(和自动拳击,这也导致难以遵循的行为,特别是与varargs结合使用)已经在Java的生命中被拴住了,这是它所展示的一个领域.所以它在规范中比在编译器中更像是一个错误.

至少,它会带来好的(?)SCJP技巧问题.

  • 实际上,它被承认为编译器错误,现在已经修复了错误. (5认同)