错误与可变参数和重载?
在Java可变参数实现中似乎存在一个错误。 当一个方法被重载时,Java不能区分适当的types和不同types的可变参数。
它给了我一个错误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"); } }
该文档说:“一般来说,你不应该重载可变参数方法,否则程序员很难找出哪个重载被调用。
但是他们没有提到这个错误,也不是程序员发现它很困难,而是编译器。
想法?
编辑 – 编译器:Sun jdk 1.6.0 u18
在Sun论坛上有关于此的讨论 。
没有真正的解决scheme,只是辞职。
可口可乐(和自动装箱,这也导致难以遵循的行为,特别是结合可变参数)后来在Java的生活中已经被狂奔,这是一个领域。 所以它在规范中比在编译器中更像是一个bug。
至less,这是很好的(?)SCJP技巧的问题。
问题是它是模棱两可的。
doIt(1, 2);
可以打电话给doIt(int ...)
或doIt(double ...)
。 在后一种情况下,整数文字将被提升为double
值。
我敢肯定,Java规范说这是一个模棱两可的结构,编译器只是遵循spec规定的规则。 (我必须进一步研究这一点。)
编辑 – JLS的相关部分是“ 15.12.2.5select最具体的方法 ”,但它让我头痛。
我认为理由是 void doIt(int[])
与void doIt(double[])
没有更具体的关系(反之亦然void doIt(double[])
因为int[]
不是double[]
的子types(反之亦然)。由于这两个重载是同样具体的,所以这个呼叫是不明确的。
相比之下, void doItAgain(int)
比void doItAgain(double)
更具体,因为int
是根据JLS的double
types。 因此,打电话给doItAgain(42)
并不含糊。
编辑2 – @finnw是对的,这是一个错误。 考虑15.12.2.5的这一部分(编辑删除不适用的情况):
一个名为m的variablesarity成员方法比另一个具有相同名称的variablesarity成员方法更具体 ,如果:
一个成员方法有n个参数,另一个成员方法有k个参数,其中n≥k。 第一个成员方法的参数types是T1,…。 。 。 ,Tn-1,Tn [],另一种方法的参数types为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承认这确实是一个错误,虽然他们已经把它定为“非常低” 。 这个bug现在在Java 7中被标记为Fixed(b123)。
有趣。 幸运的是,有几种不同的方法来避免这个问题:
您可以在方法签名中使用包装types:
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); } }
或者,您可以使用generics:
public static <T> void doit(T... ts) { for(T currT : ts) { System.out.println(currT); } }