以下是我对java中重载解析的了解:
编译器尝试解析来自给定的方法调用的过程 重载的方法定义称为重载决策。如果 编译器无法找到它找到最接近匹配的完全匹配 仅使用向上转播(从未完成向下转播)。
这是一个班级:
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
的参数?
答案 0 :(得分:19)
编译器不会考虑向下转换,而是考虑重载解析的拆箱转换。在此,Integer
i
将成功取消装箱到int
。不考虑String
方法,因为Integer
无法扩展为String
。唯一可能的重载是考虑拆箱的重载,因此打印8
。
第一个代码输出为10
的原因是编译器会考虑通过拆箱转换扩展引用转换(Integer
到Object
)。
Section 15.12.2 of the JLS,在考虑哪些方法适用时,请说明:
- 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。
醇>
- 第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱[...]
醇>
答案 1 :(得分:13)
在Java中,在方法重载的情况下解析方法的优先级如下:
<强> 1。拓宽
2.自动装箱
3.变量
java编译器认为扩展原始参数比执行自动装箱操作更令人满意。
换句话说,由于在Java 5中引入了自动装箱,编译器会在选择较新的样式之前选择较旧的样式(加宽)(自动装箱),使现有代码更加健壮。与 var-args 相同。
在您的第一个代码段中,扩展了引用变量,即
Integer
到Object
而不是解除装箱,即Integer
到int
。在第二个代码段中,从Integer
到String
不能进行扩展,因此会发生拆箱。
考虑下面的程序,该程序证明了以上所有陈述:
class MethodOverloading {
static void go(Long x) {
System.out.print("Long ");
}
static void go(double x) {
System.out.print("double ");
}
static void go(Double x) {
System.out.print("Double ");
}
static void go(int x, int y) {
System.out.print("int,int ");
}
static void go(byte... x) {
System.out.print("byte... ");
}
static void go(Long x, Long y) {
System.out.print("Long,Long ");
}
static void go(long... x) {
System.out.print("long... ");
}
public static void main(String[] args) {
byte b = 5;
short s = 5;
long l = 5;
float f = 5.0f;
// widening beats autoboxing
go(b);
go(s);
go(l);
go(f);
// widening beats var-args
go(b, b);
// auto-boxing beats var-args
go(l, l);
}
}
输出结果为:
double double double double int,int Long,Long
仅供参考,这是我的blog on method overloading in Java。
P.S:我的回答是SCJP中给出的一个例子的修改版本。
答案 2 :(得分:3)
拓宽节拍拳击,拳击节拍变速杆。在你的例子中,扩展不可能发生,所以应用的拳击和整数是未装箱的。没什么不寻常的。
答案 3 :(得分:2)
实际上在第二个例子中没有发生向下转发。发生了以下事情 -
1。整数被解包/取消装箱到原始类型int
。
2. 然后调用TestOverLoad(int a)
方法。
在main方法中,您将Integer声明为 -
Integer i = 9;
然后致电 -
test.TestOverLoad(i);
然而,您有2个重载版本的TestOverLoad()
-
TestOverLoad(int a);
TestOverLoad(String a);
此处TestOverLoad()
的第二个重载版本采用完全不同的参数String
。这就是为什么Integer
i
被取消装箱到原始类型int
的原因,然后调用第一个重载版本。
答案 4 :(得分:1)
Java中的所有对象都扩展了Object类,包括Integer类。这两个类具有以下关系:Integer“是一个(n)”对象,因为Integer扩展了Object。在第一个示例中,使用了带Object对象的方法。
在第二个示例中,未找到接受Integer的方法。在这种情况下,Java使用所谓的auto-unboxing将Integer包装类解析为原始int。因此,使用带有int参数的方法。