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
Ответы
Ответ 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 используется наиболее определенное правило метода, чтобы найти, какой метод вызывать.
Надеюсь, это поможет.