当重载包含不匹配参数的方法时,JVM将始终使用带有比参数宽的最小参数的方法。
我已经通过以下两个示例确认了上述内容:
扩展:字节扩展为int
class ScjpTest{
static void go(int x){System.out.println("In Int");}
static void go(long x){System.out.println("In long");}
public static void main (String[] args){
byte b = 5;
go(b);
}
}
装箱:将int装箱为Integer
class ScjpTest{
static void go(Integer x){System.out.println("In Int");}
static void go(Long x){System.out.println("In Long");}
public static void main (String[] args){
int b = 5;
go(b);
}
}
以上两个示例均输出正确的" In Int"。 我很困惑,但是当情况涉及var-args时,如以下示例所示
class ScjpTest{
static void go(int... x){System.out.println("In Int");}
static void go(long... x){System.out.println("In lInt");}
public static void main (String[] args){
byte b = 5; //or even with: int b = 5
go(b);
}
}
上面产生了以下错误:
ScjpTest.java:14: reference to go is ambiguous, both method go(int...) in ScjpTest and method go(long...) in ScjpTest match
go(b);
^
1 error
为什么它不应用与先前示例相同的规则? 即将字节扩展为整数,因为它是最小的大于字节的?
在Java 7上,您的最后一个示例工作正常。
var-args语法只是将数组作为参数传递的别名:
foo(int ... arg)等于foo(int[] arg)
但是数组不是分层的。 String[]不是Object[]的子类。完全相同的规则与方法参数有关。因此,编译器无法在传递byte时区分两个接受long[]和int[]的重载方法。
错误。 String []是Object []的子类。 数组在Java中是协变的(但不是泛型)。 看到我的答案:它实际上是旧Java版本中的一个错误,它不起作用。 ziggy的示例在Java 7中确实有效。
...但是实际上,此示例中的作用甚至不是数组继承,而是扩展了原始类型的转换。
正如AlexR所指出的,var-args就像一个数组。基本数组(例如byte[] short[] int[] long[] float[] double[]似乎在内部编译为同一类。这就是为什么您的重载方法不明确的原因。但是,以下代码是完全有效的:
static void go(int... x){System.out.println("In Int");}
static void go(Long... x){System.out.println("In lInt");}
这将成功编译(因为int[]和long[]是不同的类型),并产生输出In Int。
如果您正在为SCJP做准备,我强烈建议您阅读SCJP Sun认证Java 6考试310-065程序员。本书的"重载"部分介绍了混合拳击和var-args的所有技巧。
它实际上在Java 7中有效:对于varargs示例,它也返回" In Int"。我想这只是先前版本中缺少的功能。我不知道您使用的是哪个Java版本,但也许它也适用于Java 6。
但是,我必须说,即使您的第一个示例都起作用(不使用varargs),我也感到很惊讶。我不知道原始的扩大转换。
顺便说一句,如果您改为使用Byte,Integer和Long,则第一个和最后一个示例将失败,因为这些类型之间没有层次结构(只是它们都是Number的子类)。