繁体   English   中英

java中的方法重载解析

[英]Method overload resolution in java

这是我对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 呢? 为什么编译器选择将int作为参数的TestOverLoad方法,该参数是从Integer向下转换为int的参数?

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

第一个代码的输出是10的原因是编译器将考虑在拆箱转换上扩大引用转换( IntegerObject )。

JLS 的第 15.12.2 节在考虑适用哪些方法时指出:

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

  1. 第二阶段(第 15.12.2.3 节)执行重载解决方案,同时允许装箱和拆箱 [...]

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

1. 加宽
2.自动装箱
3. 可变参数

java 编译器认为扩大原始参数比执行自动装箱操作更可取。

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

在您的第一个代码片段中,发生了引用变量的扩展,即IntegerObject而不是取消装箱,即Integerint 在您的第二个片段中,从IntegerString的扩展不会发生,因此会发生拆箱。

考虑下面的程序,它证明了上述所有陈述:

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。 在您的示例中,不会发生扩大,因此对其应用的装箱和 Integer 未装箱。 没有什么不寻常的。

实际上在第二个例子中没有发生向下转换。 发生了以下事情——

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 "is a(n)" Object 因为 Integer extends Object。 在您的第一个示例中,使用了带有 Object 参数的方法。

在第二个示例中,没有找到接受整数的方法。 在这种情况下,Java 使用所谓的自动拆箱将 Integer 包装器类解析为原始 int。 因此,使用带有 int 参数的方法。

虽然@rgettman 的接受答案导致了非常正确的来源,但更准确地说, JLS 第 15.12.2 节的 §15.12.2.2 和 §15.12.2.3讨论了适用性,而不是解决方案- OP 所要求的。 在示例中,OP 提供的两个testOverLoad方法都适用,.ie 将在没有另一个方法的情况下成功解析。 相反, 15.12.2.5。 选择最具体的方法讨论了适用方法的分辨率 上面写着:

一个适用的方法 m1 比另一种适用的方法 m2 更具体,用于使用参数表达式 e1、...、ek 的调用,如果以下任何一项为真:...

m1 和 m2 可通过严格或松散调用来应用,并且 m1 具有形参类型 S1、...、Sn 和 m2 具有形参类型 T1、...、Tn,对于自变量 ei,类型 Si 比 Ti 更具体对于所有 i (1 ≤ i ≤ n, n = k)。

因此,在 OP 提供的第一个示例中,对于Integer类型的参数i方法testOverLoad(Object a)testOverLoad(int a)更具体

这是由于加宽和收窄类型铸造而发生的

加宽意味着小字体可以容纳在大字体中,而不会丢失任何信息。 扩大类型转换是自动的。 这意味着字节值可以自动转换为 short、int、long 或 double。

byte->short->int->float->double 从左到右变宽。

Java中的类型转换

希望这能回答你的问题!

您可以再查看一个示例:

公共类 HelloWorld {

void show(String c){
    System.out.println("int double overloaded method");
}

 void show(Object c){
    System.out.println("double int overloaded method");
}

}

在这里你会得到:double int 重载方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM