以下是我对java中重载解析的了解:
编译器尝试从给定的重载方法定义解析方法调用的过程称为重载解析 . 如果编译器找不到完全匹配,则仅通过使用upcast来查找最接近的匹配(从不进行向下转换) .
这是一堂课:
public class MyTest {
public static void main(String[] args) {
MyTest test = new MyTest();
Integer i = 9;
test.TestOverLoad(i);
}
void TestOverLoad(int a){
System.out.println(8);
}
void TestOverLoad(Object a){
System.out.println(10);
}
}
正如预期的那样,输出为10 .
但是,如果我稍微更改类定义并更改第二个重载方法 .
public class MyTest {
public static void main(String[] args) {
MyTest test = new MyTest();
Integer i = 9;
test.TestOverLoad(i);
}
void TestOverLoad(int a){
System.out.println(8);
}
void TestOverLoad(String a){
System.out.println(10);
}
}
输出为8 .
我在这里很困惑 . 如果永远不会使用向下转换,那为什么8会被打印出来呢?为什么编译器选择 TestOverLoad
方法,该方法将 int
作为参数从 Integer
向 int
进行向下转换?
5 回答
编译器不会考虑向下转换,而是考虑重载解析的拆箱转换 . 在这里,
Integer
i
将成功取消装箱到int
. 不考虑String
方法,因为Integer
无法扩展为String
. 唯一可能的重载是考虑拆箱的重载,因此打印8
.第一个代码的输出是
10
的原因是编译器将考虑通过拆箱转换扩展引用转换(Integer
到Object
) .Section 15.12.2 of the JLS,在考虑适用的方法时,说明:
在Java中,在方法重载的情况下解析方法是使用以下优先级完成的:
1. Widening 2. Auto-boxing 3. Var-args
java编译器认为扩展原始参数比执行自动装箱操作更令人满意 .
换句话说,在Java 5中引入 auto-boxing 时,编译器会在选择较新的样式( auto-boxing )之前选择较旧的样式( widening ),从而使现有代码更加健壮 . 与 var-args 相同 .
考虑以下程序,该程序证明了以上所有陈述:
输出是:
仅供参考,这是我的blog on method overloading in Java .
P.S:我的答案是SCJP中给出的示例的修改版本 .
加宽节拍拳击,拳击节拍var-args . 在你的例子中,扩展不可能发生,所以应用的拳击和整数是未装箱的 . 没什么不寻常的 .
实际上在第二个例子中没有发生倾斜 . 发生了以下事情 -
1. 整数被解包/取消装箱到原始类型
int
.2. 然后调用
TestOverLoad(int a)
方法 .在main方法中,您声明Integer,如 -
然后打电话 -
然而,你有2个重载版本
TestOverLoad()
-这里第二个重载版本的
TestOverLoad()
采用完全不同的参数String
. 这就是为什么Integer
i
被取消装箱到原始类型int
之后,然后调用第一个重载版本 .Java中的所有对象都扩展了Object类,包括Integer类 . 这两个类具有以下关系:Integer“是一个(n)”对象,因为Integer扩展了Object . 在第一个示例中,使用了带Object参数的方法 .
在第二个示例中,未找到接受Integer的方法 . 在这种情况下,Java使用所谓的auto-unboxing将Integer包装类解析为原始int . 因此,使用具有int参数的方法 .