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:
- 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.
- 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, writtenS >₁ T
, which is
defined by rules given later in this section. We writeS :> T
to
indicate that the supertype relation holds betweenS
andT
.
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
Spring Boot Jackson Date and Timestamp Format
Limiting Java Ssl Debug Logging
Passing Pointers Between C and Java Through Jni
Generate Uml Class Diagram from Java Project
Is Memory Leak? Why Java.Lang.Ref.Finalizer Eat So Much Memory
Kill -3 to Get Java Thread Dump
Best Option for Session Management in Java
Plsql Jdbc: How to Get Last Row Id
Junit Confusion: Use 'Extends Testcase' or '@Test'
Nextdouble() Throws an Inputmismatchexception When I Enter a Double
Differencebetween Connection and Read Timeout for Sockets
How to Create a Custom Exception Type in Java
Java 8: Where Is Trifunction (And Kin) in Java.Util.Function? or What Is the Alternative
How to Get Current Working Directory in Java
What Does the Registernatives() Method Do
Jackson Objectmapper - Specify Serialization Order of Object Properties