Overloading method calls with parameter null [duplicate] - java

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);

Related

method overloading how it decide to call which version of overloaded method in bellow case

In java, I have 2 methods which are overloaded and one is main method, so from the main method I call the overloaded method.
public class Test {
public static void main(String[] args) throws IOException {
doSomething(null);
}
private static void doSomething(Object o) {
System.out.println("method with Object in signature is called.");
}
private static void doSomething(String s) {
System.out.println("method with String in the signature is called.");
}
}
Here when I run this java code, it will call the doSomething(String s) method and it will print
method with String in the signature is called.
I think it will call doSomething(Object o) method, but it won't happen.
So can anyone explain to me this in greater detail, why this has happened and how?
Thank you.
From JLS 15.12.2.5 (emphasis added):
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 error.
Anything that can be passed to the String method can be passed to the Object method too, whilst there are things you can pass to the Object method that can't be passed to the String method (e.g. new Object()) (*); so the String method is more specific, so that is the one that is chosen.
(*) This clause is important: if you replaced the Object method with, say:
private static void doSomething(Integer s) {
then there would be things you could pass to doSomething(String) that you couldn't pass to doSomething(Integer); and there would be things you could pass to doSomething(Integer) that you couldn't pass to doSomething(String). In that case, neither is more specific, so the method invocation would be considered ambiguous.
In Java always the more specific version of method is chosen over the generic one. If the passed parameter is of type String then it will always use method with String parameter rather than generic object one.
Java follows early binding approach so during compile time it chooses the most specific method.most specific method is chosen by matching a number of parameters and type of parameter in case of method overloading.here in your case to resolve the method call type of parameter is used to resolve method call since number of parameter are equal in both methods.

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

How to prevent a method from overloading in Java?

Overriding a method can be prevented by using the keyword final, likewise how to prevent overloading?
You can't. Because it's almost pointless.
If you want to overload the method handle(..) but you are disallowed to, you'd create doHandle(..) instead.
Which overloaded method is used is determined at compile time (in contrast to overridden methods, which are determined at runtime). So the point of overloading is sharing a common name for common operations. Disallowing that is a matter of code-style, rather than anything else.
You can't do that in Java.
An overloaded method is basically just another method.
An attempt could look (something) like this
void yourMethod(String arg) { /* ... */ }
void yourMethod(String arg, Object... prevent) {
throw new IllegalArgumentException();
}
but it won't work since Java resolves overloading by looking at the "best match" or "most specific signature".
The method could still be overloaded with a
void yourMethod(String arg, String arg2) { /* ... */ }
which would be called when doing yourMethod("hello", "world").
Btw, why would you want to prevent overloading? Perhaps there is another way of doing what you want?
Err... what's the point in not allowing to Overload the method?
Protection from Overriding is allowed because it can be done by another programmer who is supposedly working on another part of code and his class is inherited from your class.
Overloading is done in the same class and is logically supposed to be done by a programmer who knows this code and is working on the same part of the code. So, if he knows this code (theoretically) and there is some inherent danger in overloading, then he should know this already because he knows the code.
That said, overloading cannot be stopped as others have already described.
Mark the class final and it can't be extended. That may defeat some other purpose though.
If you overload a method, you've created a method with the same name but different parameter types. In Java, a method is defined (partly) in terms of its parameters, and thus if two methods have the same name but different parameters, then they are apples and oranges, i.e., not the same. In short, you can't prevent someone from creating new methods in a class, which is essentially what you're asking for.
simple! don't call that overloaded method.
public class Test
{
public void m(int a)
{
*your definition*
}
public void m(float a)
{
*your definition*
}
}
public static void main(Strings [] args)
{
Test t=new Test();
t.m(5);
}
Overriding and Overloading are different techniques. Overloading is a way of declaring multiple methods with the same names but different parameter types or different no of parameters.
You can prevent a method from being overwritten by making it final, but you cannot prevent a method from being overloaded. Well technically you could make the class itself final, so that no methods at all can be added by creating a subclass but I don't think that's a good design.

How is ambiguity in selecting from overloaded methods resolved in 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?

Categories