Overload resolution, which method is called
Asked Answered
N

2

8

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.

Naughton answered 22/1, 2020 at 14:35 Comment(8)
They're similar, but different--there's no ambiguity if you pass in String, String, boolean. The most-specific method will be called. This is all in the JLS.Lithotrity
Which one is the most specific one? To my understanding, both of them are equally specific.Naughton
Please refer to JLS§15.12.2. Compile-Time Step 2: Determine Method Signature where the rules for this are described in detail. Especially 15.12.2.5. Choosing the Most Specific Method.Parlay
That said, even if the compiler and the IDEs can figure out which one is called, the rules are complex, and it's quite hard for a humarn to figure it out. So I would rename one of the methods to make it obvious.Ascomycete
Side note, java strings use just one double quote ( like "this")Deservedly
That is a really complex setup, I am pretty sure that almost no developer knows this by heart. It is most likely better to avoid any of those setups. That being said, can someone quickly try it out, which one is called? Then it may be easier to follow the JLS rules to explain which route it went and which rules were applied.Parlay
@GabrielPimenta They're not equally specific, but I did misread the signatures. In any case, the rules are still in the JLS.Lithotrity
Sorry for the double quotes guys... thats just how it was written...Naughton
D
2

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.

Deservedly answered 22/1, 2020 at 14:54 Comment(0)
P
4

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.

Pavlish answered 22/1, 2020 at 14:50 Comment(0)
D
2

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.

Deservedly answered 22/1, 2020 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.