[英]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[]
的子类型(反之亦然)。
由于这两个重载是同样特定的,因此调用是模棱两可的。
相比之下,
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)中标记为“已修复”。
有趣。 幸运的是,有两种方法可以避免此问题:
您可以在方法签名中使用包装器类型:
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.