Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload resolution, which method is called

Lets suppose I have a ComponentBase class, who is child of ObjectContextDecorator and grandchild of ObjectContext.

public class ComponentBase extends ObjectContextDecorator {
}

public class ObjectContextDecorator extends ObjectContext {

    public void set(String objectTypePath, String characteristicName, Object value) {
        //...
    }
}

public class ObjectContext {
    public void set(String characteristicName, Object value, boolean forced) {
       //...
    }
}

The set methods on ObjectContextDecorator and ObjectContext are very simillar. Consider this sample code:

ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);

Both methods' signatures fit the one being called correctly. I am not able to change the methods' signatures since it is not my code.

How does the compiler know which method I intended to call?

I know that on the IDE you can point out which method you are actually intending to call, but in this situation, I am using a class loader to load a class which has a method containing the sample code.

like image 615
Gabriel Robaina Avatar asked Jan 22 '20 14:01

Gabriel Robaina


2 Answers

It's all explained in the JLS §15.2 Method Invocation Expressions. It tells you all about how the correct method to call is chosen. And note that this does not always succeed.

In your specific case, the two methods are overloads of each other, so §15.2.2 "Compile-Time Step 2: Determine Method Signature" applies - which overload to call is determined at compile time. This step is further split into 3 phases.

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.

In the first phase, the compiler tries to find applicable methods without allowing boxing conversions. In your case, to call the overload that takes an Object, a boxing conversion is needed to convert the boolean true to the type Object, so that overload won't be chosen in the first phase.

If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (§15.12.2.3).

Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by strict invocation.

Well, we have found exactly one method, so we will just choose that method. There is no ambiguity.

like image 59
Sweeper Avatar answered Oct 09 '22 21:10

Sweeper


How does the compiler know which method I intended to call?

It checks for the arguments and determines which one is more specific following the rules described JLS §15.2

In your case, the call:

base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)

the arguments are String,String, boolean

Which matches the first class (parameters names changed for brevity)

public class ObjectContext {
    public void set(String s, Object o, boolean b){
       //...
    }
}

The second class is not invoked because the third parameter is an Object:

public class ObjectContextDecorator extends ObjectContext {

    public void set(String s, String ss, Object thisOneRightHere) {
        //...
    }
}

and while the boolean value true can match if it is autoboxed still the first one is more specific. The rule that is applying here is:

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion

But, for instance, if you use the object wrapper Boolean in the signature:

public class ObjectContext {
    public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
       //...
    }
}

Then they will both match, and the compiler would let you know with the following message:

> A.java:25: error: reference to set is ambiguous
>     base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
>         ^   both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match

But that's not the case in your example.

like image 45
OscarRyz Avatar answered Oct 09 '22 21:10

OscarRyz