java中的方法重载解析

以下是我对java中重载解析的了解:


编译器尝试从给定的重载方法定义解析方法调用的过程称为重载解析。 如果编译器找不到完全匹配,则仅通过使用upcasts来查找最接近的匹配(从不进行向下转换)。


这是一堂课:

 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。

我在这里很困惑。 如果永远不会使用downcasting ,那为什么8会被打印出来呢? 为什么编译器会选择TestOverLoad方法,该方法将int作为从Integer向int TestOverLoad的参数?

编译器将考虑不是向下转换,而是为重载解析进行拆箱转换。 在这里, Integer i将成功解包到int 。 不考虑String方法,因为无法将Integer扩展为String 。 唯一可能的重载是考虑拆箱的重载,因此打印8

第一个代码输出为10是编译器将考虑通过拆箱转换扩展引用转换( Integer to Object )。

在考虑适用哪种方法时,JLS第15.12.2节规定:

  1. 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则处理继续到第二阶段。
  1. 第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱[…]

在Java中,在方法重载的情况下解析方法是使用以下优先级完成的:

1.扩大
2.自动拳击
3.变种

java编译器认为扩展原始参数比执行自动装箱操作更令人满意。

换句话说,由于在Java 5中引入了自动装箱 ,编译器在选择较新的样式( 自动装箱 )之前选择较旧的样式( 加宽 ),从而使现有代码更加健壮。 与var-args相同。

在你的第一个代码片段中,扩展了引用变量,即Integer to Object而不是un-boxing,即Integer to int 。 在你的第二个片段中,从IntegerString扩展不会发生,因此会发生拆箱。

考虑以下程序,该程序certificate了以上所有陈述:

 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 

仅供参考,这是我的关于Java中方法重载的博客 。

PS:我的答案是SCJP中给出的示例的修改版本。

加宽节拍拳击,拳击节拍var-args。 在你的例子中,扩展不会发生,因此它应用的拳击和整数是未装箱的。 没有什么不寻常的。

实际上在第二个例子中没有发生倾斜。 发生了以下事情 –

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并且之后调用第一个重载版本。

Java中的所有对象都扩展了Object类,包括Integer类。 这两个类具有以下关系:Integer“是一个(n)”对象,因为Integer扩展了Object。 在第一个示例中,使用了带Object参数的方法。

在第二个示例中,未找到接受Integer的方法。 在这种情况下,Java使用所谓的auto-unboxing将Integer包装类解析为原始int。 因此,使用具有int参数的方法。