Why is the output like this?
Asked Answered
B

4

13
class Another {
    public void method(Object o) {
        System.out.println("This is in method which takes object");
    }
    public void method(String s) {
        System.out.println("This is method which takes string");
    }
}

public class NewClass {
    public static void main(String args[]) {
        Another an = new Another();
        an.method(null);
    }
}

When I try to execute this, I get

This is method which takes string

as the output. Why not "This is in method which takes object"? Object can also be null and string can also be null, why doesn't it invoke first method?

Begay answered 14/6, 2010 at 12:48 Comment(0)
Z
25

According to the Java Language Specification, in such cases of overloaded methods where both methods can handle the provided arguments, the method with more specific argument is chosen. Since String is more specific than Object (String extends Object), void method(String) is chosen and called.

Zennas answered 14/6, 2010 at 12:54 Comment(0)
P
7

This is exactly as specified in JLS:

JLS 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.

A String is-a Object, but not all Object is-a String. Therefore, String is more specific than Object, hence why the String overload is chosen in the above example.


It is worth noting that this exact question (in essence) appeared in the wonderful Java Puzzlers (highly recommended), specifically Puzzle 46: The Case of the Confusing Constructor

Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other

The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation. They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.


I will close with a quote from Effective Java 2nd Edition, Item 41: Use overloading judiciously:

The rules that determine which overloading is selected are extremely complex. They take up thirty-three pages in the language specification, and few programmers understand all of their subtleties.

Needless to say, this book is also highly recommended.

See also


On explicit casting

So how can I invoke the Object overload with null argument?

Simple: cast the null to type Object. There are several scenarios where this is useful/necessary, and this is one of them.

What if I have an overload that takes, say, an Integer?

Then the method invocation is ambiguous, and compile-time error occurs.

JLS 15.12.2.5 Choosing the Most Specific Method

It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case [... with some exceptions] we say that the method invocation is ambiguous, and a compile-time error occurs.

To resolve the ambiguity, again you can cast the null (or other expression) to the desired overload type.

See also

Preset answered 14/6, 2010 at 13:28 Comment(3)
Now, what if you have another method that takes a Date? Since neither String is-a Date nor Date is-a String, is the behavior unspecified? Is it an error?Garrett
@Justin: yes, it's ambiguous and therefore a compile-time error. JLS fully specifies this, and has illustrative examples.Preset
incidentally, this is the one question that I always ask in Java interviews :)Zennas
P
5

The compiler will always find the narrowest match possible when resolving overloaded method calls.

Btw the Java convention is to use uppercase names for classes, i.e. Another.

Pericynthion answered 14/6, 2010 at 12:53 Comment(1)
yep, the compiler doesn't care that you happen to be passing null, it will find the narrowest match regardless of the value of the parameter. if you wanted your method that takes an object to be called, you would need to cast explicitly.Westminster
P
1

I'm fairly certain that with Java 6 (I think Java 5 would have thrown a compiler error) in a case like this, it will select tho lowest level class to attribute the null to. (since String is an Object it is lower in the hierarchy)

Phalarope answered 14/6, 2010 at 12:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.