How is ambiguity in selecting from overloaded methods resolved in Java? - java

package org.study.algos;
public class Study {
public static void main(String[] args) {
A a = new A();
a.m1(null);
}
}
class A {
public void m1(String s) {
System.out.println("String");
System.out.println(s);
}
public void m1(Object obj) {
System.out.println("Object");
System.out.println(obj);
}
}
Here, the output is
String
null
Why does the JVM resolve the method to one with a String argument?
Thanks in advance
J

It's a fairly elaborate algorithm, detailed in JLS 15.12. But the part that is relevant here is 15.12.2, which says "the most specific one is chosen." Both the Object and String overloads are "accessible and applicable" (the String is applicable because a null literal is a reference of all types), and the String is more specific.
EDIT: Corrected section, per Syntactic.

These methods are "overloaded", not "ambiguous".
According to the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2).
And §15.12.2 says:
There may be more than one such
method, in which case the most
specific one is chosen.
String is more specific than Object, so while null is compatible with both, the method with the String parameter is chosen (there are much more complex rules that apply when the parameter types are part of a class or interface hierarchy).

null value can be set to reference of any type.
All overloaded methods you have are in one inheritance hierarchy Object <- String, the least general one is being choosen.
But if you had two overloaded methods that are not in the same hierarchy, then you'd get compilation error about ambigous methods.

A String is an Object, an Object is not a String, thus the first overload is more specific than the second. See JLS 15.12.2, as Syntactic mentioned.

I asked a similar question. Jon Skeet wrote a big answer.
The link to my question: Which overload will get selected for null in Java?

Related

What will be the output if the argument's date type is different?

What happens if the actual parameter and formal parameter's data types are different in overloading ?
Class A
{
public void m1(int i)
{
System.out.println("int");
}
public void m1(float f)
{
System.out.println("float");
}
Public static void main(String[] args)
{
A a=new A();
a.m1('a');
a.m1(10l);
}
}
The function corresponding to the arguments types gets called, this is some the basics of OOP not only in java but in all other languages.
The method with the closest matching valid signature gets called. This could well be a direct match (e.g. exactly the same function argument types), or (as in your code) the runtime knows how to automatically convert the char a to an int, so the method with the int param is called.
In overloading method resolution if the matched method with specific argument is not available the compiler won't raise any error immediately,
First it promotes the argument to the next level and check for matched method.
1)If the matched method is available then it will be considered and if it is not available then compiler once again promotes this argument to the next level.
2)This process will be continued until all the possible promotions still if the matched method is not available.Then only we will get compile error.
3)This is called automatic promotion in overloading.
The following are the possible promotions in java
Byte->short/char->int->long->
float->double

Why is this the program's output?

public class OverloadingTest extends Format{
public int add(String s1){
System.out.println("With String");
return 1;
}
public int add(Object a){
System.out.println("With Object");
return 1;
}
public static void main(String[] args) {
OverloadingTest overloadingTest = new OverloadingTest();
overloadingTest.add(null);
}
}
Why is the output of the program With String ?
I have tried reading JLS for 6th Version, but I still could not find the answer.
The only reason I could guess is that the closest match in Inheritance hierarchy is chosen.
So in this case it would take String as Object is its super class.
This answer is available in the question Method Overloading for NULL parameter:
Java will always try to use the most specific applicable version of a method that's available (see JLS §15.12.2).
So, as a result, String is used, because it's the most specific type available. If more than one subtype exists, then you will have to cast null to the appropriate type to designate which function you want to run.
This is spelled out in §15.12.2.5. Choosing the Most Specific Method:
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
In your example, add(Object) can handle anything that add(String) can. This makes the latter more specific. It is therefore the one that gets chosen to handle null.
If more than one member method is both accessible and applicable to a method invocation ... The Java programming language uses the rule that the most specific method is chosen.
See The Java Language Specification

Passing null to the method preferring String, not Object

I am facing an issue in my program and I made it clear with a small code snippet below. Can anyone explain why this is happening?
class ObjectnullTest {
public void printToOut(String string) {
System.out.println("I am null string");
}
public void printToOut(Object object)
System.out.println("I am null object");
}
class Test {
public static void main(String args[]) {
ObjectnullTest a = new ObjectnullTest();
a.printToOut(null);
}
}
This always prints I am null string .
I want to know the reason so that I can modify the code .
It's because In case of method Overloading
The most specific method is choosen at compile time.
As 'java.lang.String' is a more specific type than 'java.lang.Object'. In your case the method which takes 'String' as a parameter is choosen.
Its clearly documented in JLS:
The second step searches the type determined in the previous step for
member methods. This step uses the name of the method and the types of
the argument expressions to locate methods that are both accessible
and applicable, that is, declarations that can be correctly invoked
on the given arguments.
There may be more than one such method, in
which case the most specific one is chosen. The descriptor (signature
plus return type) of the most specific method is one used at run-time
to perform the method dispatch.
I agree with the existing comment about selection of the most specific method. You can force your null to be treated as an Object reference, eliminating use of the String argument method, by casting it:
a.printToOut((Object)null);
please see section 15.12.2.5 of jls that gives detail regarding how it is chosen
The most specific method is choosen at compile time
LINK TO THE JLS 15.12.2.5

clarification on method overloading

I have this following code and I need some clarification regarding the overloading concept.
class Overload{
static void print(Object o){
System.out.println("object");
}
static void print(String s){
System.out.println("string");
}
public static void main(String...args){
print("Hello");
}
}
when I execute this, the output is String. Eventhough object is the super class, why does it display string instead of object?
thanks in advance
The rule in this case is:
the more specific signature will apply
String is more specific than Object, that's why print(String) is used. For instance, try with print(null) in your main, you will see find out that such code will not even compile, since the compiler will have no way to distinguish whether null is a String or an Object
Check out Oracle Overloading Tutorial
There is called string print because you pass "Hello" which is String object.
String also extends regular Object but overloading calls also the most upper type.
Currently, this version of overloaded method executes:
static void print(String s){
System.out.println("string");
}
Since you are calling like this:
print("Hello");
Data conversions happen only if and only if correct version of match is not found. And exact match is found for compiler.
First JVM sees for the print(String), if not found it searches for print() with argument of superclass of String. If still not found, then super-class of super-class of String. And this algorithm continues until there is print(Object). Or reporting an error
Because when there is an exact match, during overloaded functions, JVM will not consider generalization. i.e it will look for the best fit to match the argument type. In this case "Hello" is an exact match to String type. Since String fits better in String than in Object. Hence it will not consider
static void print(Object o)

Overloading method calls with parameter null [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Method Overloading for NULL parameter
In the code below the output is
String
and if I remove the method with the parameter of type String then the output is
Object
I know how overloading of methods acts when the parameter types don't match exactly but I can not understand how null can be treated as an Object and/or a String parameter.
What is the explanation for this?
class C {
static void m1(Object x) {
System.out.print("Object");
}
static void m1(String x) {
System.out.print("String");
}
public static void main(String[] args) {
m1(null);
}
}
It always uses the most specific method according to the Java specs, section 15.12.2.5.
The intro is reasonably specific about it:
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
Generally speaking, and at least for code readability, it's always best to try to be as explicit as possible. You could cast your null into the type that matches the signature you want to call. But that's definitely a questionable practice. It assumes everyone knows this rule and makes the code more difficult to read.
But it's a good academic question, so I +1 your question.
When multiple overloads match a signature, Java picks the most specific method from among them.
The value of null matches both Object and String, but String is a subclass of Object, so String is picked. If you add another overload with a sibling of String in the class hierarchy, you'd get a compile error.\
// DOES NOT COMPILE
class C {
static void m1(Object x) {
System.out.print("Object");
}
static void m1(String x) {
System.out.print("String");
}
static void m1(Integer x) {
System.out.print("Integer");
}
public static void main(String[] args) {
m1(null);
}
}
Here is a link to a post that discusses your code example at some length.
If you need to force the call of a aprticular overloaded method when passing null as parameter, you have to cast it, like this:
m1((String)null);
By doing this, you make sure you're calling the correct overloaded version of the method.
You have to set the type of null to tell Java what function you want to call.
So you do: m1((Object) null); to call the implementation with the Object parameter and you do m1((String) null); to call the other one.
1. As String is also an object the JVM got confused to call which method at runtime.
2. If you want to specify which method to call at runtime, you can do this by explicit casting
eg:
m1((String)null);

Categories