首页 文章

java中的方法重载解析

提问于
浏览
14

以下是我对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 作为参数从 Integerint 进行向下转换?

5 回答

  • 3

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

    第一个代码的输出是 10 的原因是编译器将考虑通过拆箱转换扩展引用转换( IntegerObject ) .

    Section 15.12.2 of the JLS,在考虑适用的方法时,说明:

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

    第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱[...]

  • 13

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

    1. Widening 2. Auto-boxing 3. Var-args

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

    换句话说,在Java 5中引入 auto-boxing 时,编译器会在选择较新的样式( auto-boxing )之前选择较旧的样式( widening ),从而使现有代码更加健壮 . 与 var-args 相同 .

    在你的第一个代码片段中,扩展了引用变量,即Integer to Object而不是un-boxing,即Integer to 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中给出的示例的修改版本 .

  • 19

    加宽节拍拳击,拳击节拍var-args . 在你的例子中,扩展不可能发生,所以应用的拳击和整数是未装箱的 . 没什么不寻常的 .

  • 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 之后,然后调用第一个重载版本 .

  • 1

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

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

相关问题