Подтвердить что ты не робот

Java String.valueOf(null) вызывает NPE, но Object a = null; String.valueOf(a) возвращает 'null'

Существует ли логическое объяснение типа языка для следующего поведения (Java 7 и я подозреваю, что и предыдущие версии):

    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
4b9b3361

Ответ 1

В инструкции System.out.println(String.valueOf(null)); есть вызов метода public static String valueOf(char data[]), исходный код которого следующий:

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

Вот почему вы получаете NPE

С другой стороны, в инструкции Object a = null; String as = String.valueOf(a); есть вызовы метода public static String valueOf(Object obj), исходный код которого выглядит следующим образом:

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

Вот почему вы получаете "null" вместо NPE


Немного теории из Java Language Specification: 15.12.2.5 Выбор наиболее конкретного метода

Если более чем один метод-член доступен и применим к вызову метода, необходимо выбрать его для предоставления дескриптора для отправки времени выполнения. Язык программирования Java использует правило выбора метода наиболее специфичного.

A char[] имеет тип Object, но не все Object имеют тип char[]. Тип char[] более конкретный, чем Object, и, как описано в Спецификации языка Java, в этом случае выбирается перегрузка String.valueOf(char[]).

ИЗМЕНИТЬ

Также стоит упомянуть, что упоминал Ян Робертс (в своем комментарии ниже):

Важно отметить, что это ошибка компиляции, если нет единого перегрузка, более конкретная, чем все остальные, - если бы они были a valueOf(String), а также valueOf(Object) и valueOf(char[]), тогда вызов к нетипизированному String.valueOf(null)будет двусмысленным

Ответ 2

Первый вызов - String#valueOf(Object), второй - String#valueOf(char[])

Перегруженный метод выбирается в соответствии с аргументом статический тип, поэтому первый работает, а секунды получают NPE.

Если вы вызываете System.out.println ( String.valueOf((Object)null));, он будет работать

Ответ 3

Что из-за этого кода в классе String:

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

Ваш код (который выбрасывает NullPointerException) вызывает вышеупомянутый метод, и, таким образом, поле data null. Фактически, этот вызов вызывается классом String в конструкторе.

Используя JDK 6, исключение выглядит следующим образом:

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)

Что касается вашей строки:

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

Это работает, как называется метод ниже:

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

Очевидно, что a имеет тип Object, поэтому вызывается метод String.valueOf(Object).

Если вы специально хотите вызвать метод String.valueOf(Object obj), введите ваш нуль следующим образом:

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

Вы испытываете перегрузку метода (там, где есть несколько методов с тем же именем и сигнатурой метода, но имеют разные параметры метода). В вашем случае (где происходит NPE), JVM определяет, какой метод вызывать на основе статического типа наиболее специфического. Если тип объявлен, то самым конкретным методом является метод с тем же типом параметра объявленной переменной, иначе для JVM используется наиболее определенное правило метода, чтобы найти, какой метод вызывать.

Надеюсь, это поможет.