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.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
Gabriel Robaina
  • 709
  • 9
  • 24
  • 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. – Dave Newton Jan 22 '20 at 14:37
  • Which one is the most specific one? To my understanding, both of them are equally specific. – Gabriel Robaina Jan 22 '20 at 14:39
  • 3
    Please refer to [JLS§15.12.2. Compile-Time Step 2: Determine Method Signature](https://docs.oracle.com/javase/specs/jls/se13/html/jls-15.html#jls-15.12.2) where the rules for this are described in detail. Especially [15.12.2.5. Choosing the Most Specific Method](https://docs.oracle.com/javase/specs/jls/se13/html/jls-15.html#jls-15.12.2.5). – Zabuzard Jan 22 '20 at 14:45
  • 1
    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. – JB Nizet Jan 22 '20 at 14:46
  • 2
    Side note, java strings use just one double quote ( like `"this"`) – OscarRyz Jan 22 '20 at 14:47
  • 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. – Zabuzard Jan 22 '20 at 14:50
  • @GabrielPimenta They're not equally specific, but I did misread the signatures. In any case, the rules are still in the JLS. – Dave Newton Jan 22 '20 at 14:55
  • Sorry for the double quotes guys... thats just how it was written... – Gabriel Robaina Jan 22 '20 at 14:59

2 Answers2

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.

Community
  • 1
  • 1
Sweeper
  • 213,210
  • 22
  • 193
  • 313
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.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569