6

Possible Duplicate:
Overloaded method selection based on the parameter’s real type
How is an overloaded method choosen when a parameter is the literal null value?

When I execute the code below, I get the following output:

Method with String argument Called ..."

Why?

public class StringObjectPOC {

    public static void test(Object o)   {
        System.out.println("Method with Object argument Called ...");
    }
    public static void test(String str){
        System.out.println("Method with String argument Called ...");
    }
    public static void main(String[] args) {
        StringObjectPOC.test(null);
    }
}
Community
  • 1
  • 1
Alpesh Gediya
  • 3,706
  • 1
  • 25
  • 38
  • So you have an overloaded method 'test' and you called it with a string, but you want to know why the object one did not get called? – JoshRagem Oct 30 '12 at 05:33
  • It's just because the `String` class is a specialized form of the `Object` class (owing to the fact that the `String` class has every feature of the `Object` class in addition to its own) which is chosen by the compiler as specified by the JLS (the most specific method is chosen which is in your case, the one that accepts a parameter of type `String`). – Lion Oct 30 '12 at 05:41
  • 1
    These are also the similar threads you may want to refer to [How is an overloaded method choosen when a parameter is the literal null value?](http://stackoverflow.com/q/13033037/1037210), [Using null to overload methods in Java](http://stackoverflow.com/q/13041042/1037210) – Lion Oct 30 '12 at 06:05
  • Theoretically null reference is not of any type, then why JVM chooses String not Object. I think as Object is base for every classes in Java then It should invoke method with Object argument. – Alpesh Gediya Oct 30 '12 at 06:06
  • 1
    @Alpesh Gediya - That's because `null` in your case can be resolved to both `String` as well as to `Object`. Doesn't it? (both `Object` and `String` can be `null`) Therefore, the most specific method is chosen by the compiler as specified in the Java language specification (JSL) and the most specific method in your case is the one that accepts a `String` parameter. – Lion Oct 30 '12 at 06:08

5 Answers5

3

The null in the call matches both the test() signatures. You have to cast the null to ensure it calls one or the other.

Zagrev
  • 2,000
  • 11
  • 8
  • 4
    Java will also try to use the most specific version of a method that is available. This is why it choses String rather than Object. – slipperyseal Oct 30 '12 at 05:34
  • I'm used to Eclipse telling me to fix it before I get the chance to wrote this sort of code too. – Zagrev Oct 30 '12 at 05:46
3

A similar example is from Java Puzzles if I recall correctly.

null can be of String type or Object type. But the JVM will always choose a more accurate method.

In this case, String is more accurate then Object. (a String is an Object, but an Object might not be a String).

It is not a good habit to write code like this. Try to cast parameters to match your desired method, like

public class StringObjectPOC {

    public static void test(Object o)   {
        System.out.println("Method with Object argument Called ...");
    }
    public static void test(String str){
        System.out.println("Method with String argument Called ...");
    }
    public static void main(String[] args) {
        StringObjectPOC.test((Object)null);
    }
}
onemach
  • 4,265
  • 6
  • 34
  • 52
2

Java tries to find the most specific method possible to call. String is a subclass of object, so Java will defer to the String method whenever it can. null is a perfectly acceptable value for either an Object or a String, but since a String is more specific than an Object, Java defers to the String method because it is more precise.

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
2

I tried this:

Test2.class

public class Test2{}

Test3.class

public class Test3 extends Test2{

}

Test.class

public class Test{

public static void print(Object obj){
    System.out.println("Object");
}

public static void print(Test2 obj){
    System.out.println("test 2");
}

public static void print(Test3 obj){
    System.out.println("Test 3");
}


public static void main(String[]args){
    Test.print(null);
}

}

it printed out Test 3

Just like in your scenario, this means that if a method is overloaded (and when null is passed), it recognizes the method which has the child-most parameter.

Object->Test->Test2

or in your case:

Object->String
Russell Gutierrez
  • 1,372
  • 8
  • 19
1

null is could be both a String and/or an Object but because String inherits from Object, it will try to use the signature that is more precise. You can cast null to choose which method to execute:

public static void main(String[] args) {
    Test.test((Object) null); // treats as Object
    Test.test((String) null); // treats as String
    Test.test(null);          // treats as String
}
doublesharp
  • 26,888
  • 6
  • 52
  • 73