Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method overload resolution in java

Here is what I know about overload resolution in 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.

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.

Here I am confused. If downcasting was never to be used, then why did 8 get printed at all? Why did compiler pick up the TestOverLoad method which takes int as an argument which is a downcast from Integer to int?

like image 324
ayush Avatar asked May 07 '15 18:05

ayush


People also ask

Can overloaded methods have different return types Java?

No, you cannot overload a method based on different return type but same argument type and number in java.

How can we prevent method overloading in Java?

The final way of preventing overriding is by using the final keyword in your method. The final keyword puts a stop to being an inheritance. Hence, if a method is made final it will be considered final implementation and no other class can override the behavior.

Why method overloading is not possible by changing the return type in Java?

In java, method overloading is not possible by changing the return type of the method only because of ambiguity.


3 Answers

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. The String method isn't considered because an Integer cannot be widened to a String. The only possible overload is the one that considers unboxing, so 8 is printed.

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.

Section 15.12.2 of the JLS, when considering which methods are applicable, states:

  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. 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 [...]
like image 128
rgettman Avatar answered Sep 19 '22 07:09

rgettman


In Java, resolving methods in case of method overloading is done with the following precedence:

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

The java compiler thinks that widening a primitive parameter is more desirable than performing an auto-boxing operation.

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. Same is with var-args.

In your 1st code snippet, widening of reference variable occurs i.e, Integer to Object rather than un-boxing i.e, Integer to int. And in your 2nd snippet, widening cannot happen from Integer to String so unboxing happens.

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.

P.S: My answer is a modified version of an example given in SCJP.

like image 21
Ram Patra Avatar answered Sep 22 '22 07:09

Ram Patra


widening beats boxing, boxing beats var-args. In your example, the widening cannot happen, so the boxing it's applied and Integer is unboxed. Nothing unordinary.

like image 35
Silviu Burcea Avatar answered Sep 23 '22 07:09

Silviu Burcea