Method Overload Resolution in Java

Method overload resolution in java

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 [...]

Overload resolution, which method is called

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.

Why is method overload resolution determined at compile time?

I have not read the minds of the language designers, so cannot really tell you. I am thinking of it in this way:

  • Overridden methods are different implementations of the same method at different levels in the superclass/subclass hierarchy. The subclass generally uses the same method signature (it’s allowed to return a more specific type and to declare fewer exceptions to be thrown, but it cannot completely redefine the method header, or it will no longer be an override).
  • Overloaded methods are really just different methods that happen to have the same name. Then the parameter types are used for distinguishing. Just like the compiler always decides on compile time which method to call, this is also the case with overloaded methods.

As an observation (possibly a minor one), with runtime resolution of overloaded methods we could no longer statically type check the return value. Imagine we have

public boolean foo(Number n);
public String foo(Integer i);

Now I would find it perfectly natural to call the former foo() like this:

    boolean result = foo(myNumber);

Now if myNumber happened to be an Integer, the latter foo() would be called instead. It would return a String and I would have a type conversion error happening on runtime. I would not be amazed.

… why then we can still have runtime polymorphism and it be considered
static typing, but it wouldn't be if we did dynamic resolution of
overloaded methods.

Java has both: a static type and a runtime type. When I store an Integer into a variable declared to be a Number, then Number is the static type and Integer is the runtime type (BTW a type is not the same as a class). And you are correct, when I do myObject.foo(arg), then the runtime type of myObject decides which implementation of foo() gets called. And conceivably the runtime type of arg could have been involved in the decision too. It would get more complicated, and I am unsure about the gain.

Is dynamic overload resolution possible in Java?

Overriding is what has dynamic binding in Java. Overloading has static binding, and which function is called is determined at compile time, not at runtime. See this SO question.

Therefore you can't use overloading for run time selection of methods. Suggest you use one of the other OOP design patterns in java, or at least instanceof:

public void dispatch(Object o)
{
if (o instanceof String)
handleString((String)o);
else if (o instanceof File)
handleFile((File)o);
else
handleObject(o);
}

Why Method Overload Resolution have to be done at compile time in JAVA?

The short version is because that's how the Java system decided to do it (among other things, it's a lot faster at runtime). Groovy (among other JVM languages) can do dynamic dispatch, and invokedynamic was added to the JVM instruction set in Java 7 to help make this sort of approach more efficient.

Overload resolution with method references and function interface specializations for primitive types

For primitive types, the clause "R1 <: R2" is defined in 4.10.1 according to the size of the types. There is no relation between double and int, so this case does not define which type is more specific.

This is not the case; double is, in fact, a supertype of int.

Paragraph 4.10:

The supertypes of a type are obtained by reflexive and transitive
closure
over the direct supertype relation, written S >₁ T, which is
defined by rules given later in this section. We write S :> T to
indicate that the supertype relation holds between S and T.

Paragraph 4.10.1:

The following rules define the direct supertype relation among the
primitive types:

double >₁ float

float >₁ long

long >₁ int

The supertype relation being a reflexive and transitive closure of the direct supertype relation means that from (double >₁ float) ∧ (float >₁ long) ∧ (long >₁ int) follows double :> int.

How to choose overloaded method by argument type?

Method overloading resolution is performed at compile time, when only the compile-time type is known. Therefore, the compile-time type of the parameters passed to the method call determine which of the overloaded methods is chosen.

Since you are passing elements of a List<ObjectError> to the method call, String getMessage(final ObjectError objectError) is always chosen, and the runtime type of the instances stored in that List doesn't make a difference.

One way to solve your problem is to move the getMessage() method to ObjectError class, and override it in the FieldError sub-class.

Instead of

getMessage(errors.get(0))

you'll call

errors.get(0).getMessage()

This will work, since method overriding is resolved at runtime.

Overloaded methods for java certification exam

If you remove the method add(int a, long... b) you will find that your code won't compile because the remaining method add(int a, Long b) cannot be called with add(1, 2) because 2 is an int and a primitive int cannot be boxed into a Long. Likewise, the statement Long a = 2; is invalid. Therefore the only matching candidate is add(int a, long... b).

JAVA function overloading with generic type issue

The value 'A' is of type char. In Java, char is a numeric type, so it can be assigned to int. Furthermore, when there are two overloaded methods - one taking int, the other taking the boxed type Character - you will get the int one:

class Test {
static void method(int a) {
System.out.println("int");
}
static void method(Character a) {
System.out.println("Character");
}
}
> Test.method('A');
int

In particular, the integer value of 'A' is 65, since that's its Unicode value. So you are actually calling the add(int) method with the value 65, not the add(Character) method, hence the IOOBE.

To fix it, either cast to Character explicitly when calling the method, or change the names to addByIndex and addByValue so that Java won't select the wrong one based on the argument types.


To understand why Java chooses the add(int) method instead of add(Character), requires wading through the Java Language Specification. Section §15.12 specifies how method calls are resolved:

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.

So the add(int) method matches in the first phase because converting from a char to an int is not a boxing or unboxing conversion; and that method is chosen without proceeding to the second stage of method resolution where the boxing conversion from char to Character would be allowed.

overload resolution ambiguity when function parameter is marked NonNull

From kotlin in action

sometimes Java code contains information about nullability, expressed
using annotations. When this information is present in the code,
Kotlin uses it. Thus @Nullable String in Java is seen as String? by
Kotlin, and @NotNull String is just String. The interesting
question is what happens when the annotations aren’t present. In that case, the
Java type becomes a platform type in Kotlin.

When you use Java declarations from Kotlin, Java primitive types
become non-null types (not platform types), because they can’t hold
null values.

in your case first method has a java primitve type as parameter and because primitives can't be null kotlin translates it to

setX(x: Int)

and since second method contains @Nonnull annotation, kotlin uses this information and hence it translates the method to

setX(x: Int)

so as you can see for kotlin they are two different methods with exact same signature, hence the ambiguity.



Related Topics



Leave a reply



Submit