Why do different return types not count as method overloading in Java?

Posted by Humpty on Wed, 05 Jan 2022 03:42:58 +0100

This article has included "Java common interview questions": https://gitee.com/mydb/interview

Method overloading means that multiple methods with the same name are defined in the same class, but the parameter type or number of parameters of each method is different.
For example, the following four method methods can be called method overloading, as shown in the following code:

public class OverloadExample {
    public void method() {
        // doSomething
    }

    public void method(String name) {
        // doSomething
    }

    public void method(Integer id) {
        // doSomething
    }

    public void method(Integer id, String name) {
        // doSomething
    }
}

Why do different return types not count as method overloading?

To answer this question, we must first understand a bit of the front content, method signature.
Method signature is a unique value composed of method name + parameter type + number of parameters. This unique value is the method signature, and the JVM (Java virtual machine) determines which method to call through this method signature.
From the composition rules of method signature, we can see that the return type of a method is not a part of the method signature. Therefore, when there are multiple methods with the same method name and parameters but different return value types in the same class, the JVM cannot judge which method to call through the method signature, as shown in the following figure:

So why can't a return type be part of a method signature?
The reason is actually very simple. Imagine that if the return type of the method is also part of the method signature, when the programmer writes a code to call the "overloaded" method, the JVM cannot distinguish which method to call, as shown in the following code:

public class OverloadExample {
    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.method("Brother Lei"); // Which method should the JVM call?
    }

    public int method(String name) {
        // doSomething
        return 666;
    }

    public String method(String name) {
        // doSomething
        return "Brother Lei talking about programming";
    }
}

In the above case, the JVM cannot infer which method to call, so the return type of the method cannot be part of the method signature.

Usage scenario of method overloading

The classic usage scenario of method overloading is the valueOf method of String type. There are 9 implementations of valueOf method overloading, as shown in the following figure:

It can convert arrays, objects, and underlying data types to string types.

Method overload matching principle

The calling sequence of method overloading can be divided into front and back, such as the following code:

public class OverloadExample {
    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.method(12);
    }

    public void method(int num) {
        System.out.println("call int method");
    }

    public void method(long num) {
        System.out.println("call long method");
    }

    public void method(Integer num) {
        System.out.println("call Integer method");
    }

    public void method(Object num) { 
        System.out.println("call Object method");
    }

    public void method(int... num) { // Optional parameters
        System.out.println("call int... method");
    }
}

When method overloading occurs, which method does the program call? The results of the above procedures are as follows:

Therefore, we can draw the following conclusions.

Matching principle 1: accurate type matching

Method overload calls as like as two peas of parameter types. This is the first priority matching principle: precise type matching.

Matching principle 2: base types are automatically converted to larger base types

Next, we delete the exact matching method and observe the second matching order? The implementation code is as follows:

public class OverloadExample {
    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.method(12);
    }

    public void method(long num) {
        System.out.println("call long method");
    }

    public void method(Integer num) {
        System.out.println("call Integer method");
    }

    public void method(Object num) { 
        System.out.println("call Object method");
    }

    public void method(int... num) { // Optional parameters
        System.out.println("call int... method");
    }
}

The execution results of the above procedures are shown in the figure below:

Therefore, we can conclude that if it is a basic data type, the second matching principle of method overload call is to automatically convert to a larger basic data type.

Matching principle 3: automatic packing / unpacking matching

Next, delete the long method in the second matching principle, and the implementation code is as follows:

public class OverloadExample {
    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.method(12);
    }

    public void method(Integer num) {
        System.out.println("call Integer method");
    }

    public void method(Object num) {
        System.out.println("call Object method");
    }

    public void method(int... num) { // Optional parameters
        System.out.println("call int... method");
    }
}

The execution results of the above procedures are shown in the figure below:

As can be seen from the above execution results, the third matching principle of method overloading is to match the data type of automatic boxing or unpacking.

Matching principle 4: match up according to the inheritance route

At this time, delete the Integer method in the third matching principle, and the remaining code is as follows:

public class OverloadExample {
    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.method(12);
    }

    public void method(Object num) {
        System.out.println("call Object method");
    }

    public void method(int... num) { // Optional parameters
        System.out.println("call int... method");
    }
}

The execution results of the above procedures are shown in the figure below:

As can be seen from the above execution results, the fourth matching principle of method overloading is to match the method calls of the parent class upward in turn.

Matching principle 5: variable parameter matching

Finally, the method in the code is deleted, leaving only one optional parameter. The implementation code is as follows:

public class OverloadExample {
    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.method(12);
    }

    public void method(int... num) { // Optional parameters
        System.out.println("call int... method");
    }
}

The execution results of the above procedures are shown in the figure below:

As can be seen from the above execution results, the fifth matching principle of method overloading is to match optional parameters.

summary

Multiple methods with the same name are defined in the same class, but the parameter type or number of parameters of each method is different, which is method overloading. The typical use scenario of method overloading is the valueOf method in String, which has nine implementations. The method return type cannot be used as a basis for method overloading because it is not part of the method signature. There are five matching principles for method overloading: accurate matching, automatic conversion of basic type to larger basic type matching, automatic packing / unpacking matching, upward matching according to inheritance route, and variable parameter matching.
‚Äč

Reference: code out efficiency

Right and wrong are judged by ourselves, bad reputation is heard by others, and the number of gains and losses is safe.

The official account: Java interview