36

Is there a logical language-design-type explanation for the following behaviour (Java 7 and I suspect earlier editions as well):

    Object  a = null;
    String as = String.valueOf(a);              // as is assigned "null"
    System.out.println(as+":"+as.length());     // prints: "null:4"
    System.out.println ( String.valueOf(null)); // NPE
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331

3 Answers3

44

In statement System.out.println(String.valueOf(null)); there is a call of method public static String valueOf(char data[]), which source code is as follows:

public static String valueOf(char data[]) {
  return new String(data);
}

That is why you get NPE

On the other hand, in statement Object a = null; String as = String.valueOf(a); there is a calls of method public static String valueOf(Object obj), which source code is as follows:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

That is why you get "null" instead of NPE


A bit of theory from Java Language Specification: 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 char[] is of type Object, but not all Object are of type char[]. Type char[] is more specific than Object and as described in the Java Language Specification, the String.valueOf(char[]) overload is chosen in this case.

EDIT

It is also worth mentioning what Ian Roberts mentioned (in his comment below):

It's important to note that it's a compile error if there is no single overloading that is more specific than all the others - if there were a valueOf(String) method as well as valueOf(Object) and valueOf(char[]) then a call to the untyped String.valueOf(null) would be ambiguous

Community
  • 1
  • 1
Tom
  • 26,212
  • 21
  • 100
  • 111
  • 6
    It's important to note that it's a compile error if there is no single overloading that is more specific than all the others - if there were a `valueOf(String)` method as well as `valueOf(Object)` and `valueOf(char[])` then a call to the untyped `String.valueOf(null)` would be ambiguous. – Ian Roberts Jan 02 '13 at 15:32
15

The first invocation is to String#valueOf(Object), the second is to String#valueOf(char[])

The overloaded method is chosen according to the argument's static type, this is why the first works and the seconds get an NPE.

If you invoke System.out.println ( String.valueOf((Object)null)); it will work

BryanH
  • 5,826
  • 3
  • 34
  • 47
Aviram Segal
  • 10,962
  • 3
  • 39
  • 52
7

That's because of this code in String class:

public static String valueOf(char data[]) {
return new String(data);
}

Your code (which throws NullPointerException) calls the above-mentioned method and, thus, the data field is null. In fact, this call is thrown by the String class on constructor.

Using JDK 6, the exception is as follows:

java.lang.NullPointerException
    at java.lang.String.<init>(String.java:177)
    at java.lang.String.valueOf(String.java:2840)
    at org.bfs.data.SQLTexter.main(SQLTexter.java:364)

As for your line:

System.out.println(as+":"+as.length());     // prints: "null:4"

This works as the below method is called:

public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

Obviously, a is of type Object so the String.valueOf(Object) method is called.

If you specifically want to call String.valueOf(Object obj) method, typecast your null as follows:

System.out.println (String.valueOf((Object)null));

You're experiencing method overloading (where there are several method with the same name and method signature, but have different method parameters). In your case (where NPE occurs), the JVM determines which method to call based on the most specific static type. If the type is declared, then the most specific method is the method with the same parameter type of the declared variable, else, a most specific method rule is used by the JVM to find which method to invoke.

I hope this helps.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228