简体   繁体   English

java中的方法重载解析

[英]Method overload resolution in java

Here is what I know about overload resolution in java:这是我对java中重载解析的了解:


The process of compiler trying to resolve the method call from given overloaded method definitions is called overload resolution.编译器试图从给定的重载方法定义中解析方法调用的过程称为重载解析。 If the compiler can not find the exact match it looks for the closest match by using upcasts only (downcasts are never done).如果编译器找不到精确匹配,它只使用向上转换来寻找最接近的匹配(向下转换永远不会完成)。


Here is a class:这是一个类:

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);
    }

}

As expected the output is 10.正如预期的那样,输出为 10。

However if I change the class definition slightly and change the second overloaded method.但是,如果我稍微更改类定义并更改第二个重载方法。

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);
    }

}

The output is 8.输出为 8。

Here I am confused.在这里我很困惑。 If downcasting was never to be used, then why did 8 get printed at all?如果从不使用向下转换,那么为什么要打印 8 呢? Why did compiler pick up the TestOverLoad method which takes int as an argument which is a downcast from Integer to int ?为什么编译器选择将int作为参数的TestOverLoad方法,该参数是从Integer向下转换为int的参数?

The compiler will consider not a downcast, but an unboxing conversion for overload resolution.编译器不会考虑向下转换,而是考虑重载解析的拆箱转换。 Here, the Integer i will be unboxed to an int successfully.在这里, Integer i将成功拆箱为int The String method isn't considered because an Integer cannot be widened to a String .不考虑String方法,因为Integer不能扩展为String The only possible overload is the one that considers unboxing, so 8 is printed.唯一可能的重载是考虑拆箱的重载,因此打印8

The reason that the first code's output is 10 is that the compiler will consider a widening reference conversion ( Integer to Object ) over an unboxing conversion.第一个代码的输出是10的原因是编译器将考虑在拆箱转换上扩大引用转换( IntegerObject )。

Section 15.12.2 of the JLS , when considering which methods are applicable, states: JLS 的第 15.12.2 节在考虑适用哪些方法时指出:

  1. The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation.第一阶段(第 15.12.2.2 节)执行重载决议,不允许装箱或拆箱转换,或使用变量 arity 方法调用。 If no applicable method is found during this phase then processing continues to the second phase.如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

  1. The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing [...]第二阶段(第 15.12.2.3 节)执行重载解决方案,同时允许装箱和拆箱 [...]

In Java, resolving methods in case of method overloading is done with the following precedence:在 Java 中,在方法重载的情况下解析方法按以下优先级完成:

1. Widening 1. 加宽
2. Auto-boxing 2.自动装箱
3. Var-args 3. 可变参数

The java compiler thinks that widening a primitive parameter is more desirable than performing an auto-boxing operation. java 编译器认为扩大原始参数比执行自动装箱操作更可取。

In other words, as auto-boxing was introduced in Java 5, the compiler chooses the older style( widening ) before it chooses the newer style( auto-boxing ), keeping existing code more robust.换句话说,由于在 Java 5 中引入了自动装箱,编译器会在选择较新的样式(自动装箱)之前选择较旧的样式(加宽),从而使现有代码更加健壮。 Same is with var-args . var-args也是如此。

In your 1st code snippet, widening of reference variable occurs ie, Integer to Object rather than un-boxing ie, Integer to int .在您的第一个代码片段中,发生了引用变量的扩展,即IntegerObject而不是取消装箱,即Integerint And in your 2nd snippet, widening cannot happen from Integer to String so unboxing happens.在您的第二个片段中,从IntegerString的扩展不会发生,因此会发生拆箱。

Consider the below program which proves all the above statements:考虑下面的程序,它证明了上述所有陈述:

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);
    }
}

The output is:输出是:

double double double double int,int Long,Long

Just for reference, here is my blog on method overloading in Java .仅供参考,这是我关于 Java 中方法重载的博客

PS: My answer is a modified version of an example given in SCJP. PS:我的答案是 SCJP 中给出的示例的修改版本。

widening beats boxing, boxing beats var-args.扩大节拍拳击,拳击节拍 var-args。 In your example, the widening cannot happen, so the boxing it's applied and Integer is unboxed.在您的示例中,不会发生扩大,因此对其应用的装箱和 Integer 未装箱。 Nothing unordinary.没有什么不寻常的。

Actually in the second example no downcasting is occurred.实际上在第二个例子中没有发生向下转换。 There occurred the following thing -发生了以下事情——

1. Integer is unwrapped/unboxed to primitive type int . 1.整数被解包/拆箱为原始类型int
2. Then the TestOverLoad(int a) method is called. 2 、然后TestOverLoad(int a)方法。

In main method you declare Integer like -在 main 方法中,您声明 Integer 像 -

 Integer i = 9;  

Then call -然后打电话——

test.TestOverLoad(i);  

Whereas, you have 2 overloaded version of TestOverLoad() -而您有 2 个重载版本的TestOverLoad() -

TestOverLoad(int a); 
TestOverLoad(String a);

Here the second overloaded version of TestOverLoad() takes completely different argument String .这里TestOverLoad()的第二个重载版本采用完全不同的参数String Thats why Integer i is unboxed to a primitive type int and after that the first overloaded version is called.这就是为什么Integer i被拆箱为原始类型int ,然后调用第一个重载版本。

All objects in Java extend the class Object, including the class Integer. Java 中的所有对象都扩展了 Object 类,包括 Integer 类。 These two class have the following relationship: Integer "is a(n)" Object because Integer extends Object.这两个类有如下关系: Integer "is a(n)" Object 因为 Integer extends Object。 In your first example, the method with Object parameter is used.在您的第一个示例中,使用了带有 Object 参数的方法。

In the second example, no methods are found that accept an Integer.在第二个示例中,没有找到接受整数的方法。 In this case Java uses what is called auto-unboxing to resolve the Integer wrapper class to a primitive int.在这种情况下,Java 使用所谓的自动拆箱将 Integer 包装器类解析为原始 int。 Thus, the method with the int parameter is used.因此,使用带有 int 参数的方法。

While accepted answer of @rgettman leads to very right source, more precisely, §15.12.2.2 and §15.12.2.3 of the JLS Section 15.12.2 discuss the applicability , not the resolution - what the OP asked for.虽然@rgettman 的接受答案导致了非常正确的来源,但更准确地说, JLS 第 15.12.2 节的 §15.12.2.2 和 §15.12.2.3讨论了适用性,而不是解决方案- OP 所要求的。 In the example the OP provided both testOverLoad methods are applicable , .ie will be successfully resolved in the absence of another one.在示例中,OP 提供的两个testOverLoad方法都适用,.ie 将在没有另一个方法的情况下成功解析。 Instead, 15.12.2.5.相反, 15.12.2.5。 Choosing the Most Specific Method discusses the resolution of the applicable methods. 选择最具体的方法讨论了适用方法的分辨率 It reads:上面写着:

One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true: ...一个适用的方法 m1 比另一种适用的方法 m2 更具体,用于使用参数表达式 e1、...、ek 的调用,如果以下任何一项为真:...

m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k). m1 和 m2 可通过严格或松散调用来应用,并且 m1 具有形参类型 S1、...、Sn 和 m2 具有形参类型 T1、...、Tn,对于自变量 ei,类型 Si 比 Ti 更具体对于所有 i (1 ≤ i ≤ n, n = k)。

So, in the first example, provided by OP, for parameter i of type Integer method testOverLoad(Object a) is more specific than testOverLoad(int a) .因此,在 OP 提供的第一个示例中,对于Integer类型的参数i方法testOverLoad(Object a)testOverLoad(int a)更具体

This is happening due to Widening and Narrowing Type casting这是由于加宽和收窄类型铸造而发生的

Widening means a small type can be accommodated in a larger type without any loss of information.加宽意味着小字体可以容纳在大字体中,而不会丢失任何信息。 Widening Typecasting is automatic.扩大类型转换是自动的。 That means a byte value can be automatically casted to short, int, long or double.这意味着字节值可以自动转换为 short、int、long 或 double。

byte->short->int->float->double Widens from left to right. byte->short->int->float->double 从左到右变宽。

Type Casting in Java Java中的类型转换

Hope this answers your question!希望这能回答你的问题!

you can check with one more example :您可以再查看一个示例:

public class HelloWorld {公共类 HelloWorld {

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

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

}

here the you will get : double int overloaded method在这里你会得到:double int 重载方法

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

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