Почему String.valueOf (null) вызывает исключение NullPointerException?


127

согласно документации метод String.valueOf(Object obj)возвращает:

если аргумент равен null, то строка равна "null"; в противном случае obj.toString()возвращается значение.

Но почему, когда я пытаюсь сделать это:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

вместо этого бросает NPE? (попробуйте сами, если не верите!)

    Исключение в потоке "main" java.lang.NullPointerException
    в java.lang.String. (Неизвестный источник)
    в java.lang.String.valueOf (Неизвестный источник)

Как так получилось? Врет ли мне документация? Это серьезная ошибка в Java?

Ответы:


201

Проблема в том, что String.valueOfметод перегружен :

Язык спецификаций Java требует, чтобы в таких случаях выбиралась наиболее конкретная перегрузка :

JLS 15.12.2.5 Выбор наиболее конкретного метода

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

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

String.valueOf(char[])ожидает, что массив не будет null, и, поскольку nullв этом случае задан, он выбрасывает NullPointerException.

Простое «исправление» - это nullявно привести к Objectследующему:

System.out.println(String.valueOf((Object) null));
// prints "null"

Связанные вопросы


Мораль истории

Вот несколько важных:

  • Эффективное 2-е издание Java, пункт 41: разумно используйте перегрузку
    • То, что вы можете перегрузить, не означает, что вам следует каждый раз
    • Они могут вызвать путаницу (особенно если методы делают совершенно разные вещи).
  • Используя хорошую IDE, вы можете проверить, какая перегрузка выбрана во время компиляции.
    • С Eclipse, вы можете мыши при наведении курсора на приведенном выше выражении , и видим , что на самом деле , то valueOf(char[])выбирается перегрузка!
  • Иногда вы хотите явно использовать приведение null(примеры для подражания)

Смотрите также


На кастинге null

Существует как минимум две ситуации, когда необходимо явное приведение nullк конкретному ссылочному типу:

  • Чтобы выбрать перегрузку (как показано в примере выше)
  • Чтобы передать nullв качестве единственного аргумента параметр vararg

Простой пример последнего:

static void vararg(Object... os) {
    System.out.println(os.length);
}

Тогда у нас может быть следующее:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

Смотрите также

Связанные вопросы


5
Другое предложение: когда вы перегружаете метод и один аргумент может быть вызван для двух перегрузок (например, nullв этом случае), убедитесь, что обе перегрузки действуют одинаково в отношении этого значения!
Joachim Sauer

3
@Joachim: Я только что прочитал эту статью и был приятно удивлен, обнаружив, что эти два метода были подробно обсуждены! Блох пошел еще дальше и заявил, что с тех пор, как String.valueOf(Object)и в valueOf(char[])любом случае (независимо от того nullили нет), они, возможно, не должны были быть перегрузками.
polygenelubricants

Возник вопрос ... если у вас есть метод, который возвращает объект, тогда оператор return null;будет точно таким же, как return (Object) null;?
user972276

17

Проблема в том, что ты звонишь, String.valueOf(char[])а нет String.valueOf(Object) .

Причина этого в том, что Java всегда будет выбирать наиболее конкретную версию перегруженного метода, которая работает с предоставленными параметрами. null- допустимое значение для Objectпараметра, но это также допустимое значение для char[]параметра.

Чтобы заставить Java использовать Objectверсию, либо перейдите nullчерез переменную, либо укажите явное приведение к Object:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));

5

Ошибка под номером 4867608 была зарегистрирована для этого способа еще в 2003 году, которая была решена как «не исправить» с этим объяснением.

Мы не можем изменить это из-за ограничений совместимости. Обратите внимание, что в конечном итоге вызывается общедоступный статический метод String valueOf (char data []), и в нем не упоминается замена «null» на нулевые аргументы.

@ ###. ### 23.05.2003


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.