首先让我们来看一个例子(以下的输出结果基于jdk6版本):
class EasyOver
{
static void go(int x){
System.out.println("int ");
}
static void go(long x){
System.out.println("long ");
}
static void go(double x){
System.out.println("double ");
}
public static void main(String[] args)
{
byte b = 5;
short s = 5;
long l = 5;
float f = 5.0f;
go(b);
go(s);
go(l);
go(f);
}
}
对于上面的调用将会产生什么样的输出呢?相信对重载有一点了解的人可以很轻松的就写出输出结果:
int
int
long
double
这种结果我们一看就知道了,并且也不是那么令人惊讶,应为使用byte和short变元的调用被隐式加宽,以匹配带int的go()方法的版本,当然带long变元的调用会使用go()方法的long版本,最后,是用float变元的调用会与带double变元的方法匹配。
但是对于如下的带有装箱变元的go方法呢?
class AddBoxing{
static void go(Integer x){
System.out.println("Integer ");
}
static void go(long x){
System.out.println("long");
}
public static void main(String args[]){
int i = 4;
go(i);
}
}
对于如上的代码将会产生怎样的输出呢?是Integer还是long呢?
正如我们所理解的那样,如果只存在go()方法的Integer变元,那么毫无疑问,java5的装箱能力将允许调用成功从而输出Integer;同样仅当long版本存在时,编译器将使用它处理go()方法调用,也就是会输出long,但是两个方法都存在,就像上面那样,编译器会使用哪个方法呢?
答案是:编译器将选择加宽而不是装箱,因此输出将是:
long
对于上面的结果,相信很多读者和我最初一样也有疑问,为什么呢???
对于这个问题,根据java5的设计者的解释是:最重要的规则应该是已有代码应该像他们过去那样运行,因此,既然加宽能力已经存在,通过加宽调用的方法不应该输给新创建的依赖于装箱的方法,基于这种规则,请预测下如下输出:
class AddVarargs{
static void go(int x,int y){
System.out.println("int,int");
}
static void go(byte... x){
System.out.println("byte...");
}
public static void main(String args[]){
byte b = 5;
go(b,b);
}
}
相信聪明的你已经猜到输出是:
int,int
确实如你所想,即使每个调用都要求某种转换,在选择较新的风格之前,编译器仍将倾向于优先选择较老的风格,以保持现有代码的健壮性。
到这我们已经知道:
1、 加宽将优于装箱先执行
2、加宽优于var-arg(可变变元方法)执行
那么var-arg和装箱呢?请看下面的代码:
class BoxOrVararg
{
static void go(Byte x,Byte y){
System.out.println("Byte,Byte");
}
static void go(byte... x){
System.out.println("byte...");
}
public static void main(String[] args)
{
byte b = 4;
go(b,b);
}
}
上面的结果将是什么呢?在这我就不说了,留给读者自己探索吧
另外,对于与基本数据类型对应的包装器类型之间是否也是这样的规律呢?
关于重载,还有几点比较重要,这篇就写到这了,我会在下一篇中继续介绍,欢迎大家来一起学习!