Почему работает следующая работа? Я ожидал бы, что будет NullPointerException
.
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Почему работает следующая работа? Я ожидал бы, что будет NullPointerException
.
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
JLS 5, раздел 15.18.1.1 JLS 8 § 15.18.1 "Оператор конкатенации строк +" , приводящий к JLS 8, § 5.1.11 "Преобразование строк" , эта операция должна выполняться без сбоев:
... Теперь нужно учитывать только опорные значения. Если ссылка равна null, она преобразуется в строку "null" (четыре символа ASCII n, u, l, l). В противном случае преобразование выполняется как бы путем вызова метода toString ссылочного объекта без аргументов; но если результат вызова метода toString равен нулю, вместо этого используется строка "null".
Посмотрите на байт-код! Компилятор принимает ваш код:
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
и скомпилирует его в байт-код, как если бы вы написали это:
String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"
(Вы можете сделать это самостоятельно, используя javap -c
)
Применить методы StringBuilder
все дескриптор null просто отлично. В этом случае, поскольку null
- это первый аргумент, вместо него вызывается String.valueOf()
, поскольку StringBuilder не имеет конструктора, который принимает произвольный ссылочный тип.
Если бы вы сделали s = "hello" + s
вместо этого, эквивалентный код:
s = new StringBuilder("hello").append(s).toString();
где в этом случае метод append принимает значение null, а затем передает его на String.valueOf()
.
Примечание. Конкатенация строк на самом деле является одним из редких мест, где компилятор принимает решение о том, какую оптимизацию выполнить. Таким образом, "точный эквивалентный" код может отличаться от компилятора к компилятору. Эта оптимизация разрешена JLS, раздел 15.18.1.2:
Чтобы увеличить производительность повторной конкатенации строк, компилятор Java может использовать класс StringBuffer или подобный метод для уменьшения количества промежуточных объектов String, созданных при оценке выражения.
Компилятором, который я использовал для определения "эквивалентного кода" выше, был компилятор Eclipse, ecj.
См. раздел 5.4 и 15.18 языка Java спецификация:
Преобразование строк применяется только к операнды двоичного + оператора, когда одним из аргументов является String. В этот единственный случай, другой аргумент + преобразуется в String и новую строку, которая является конкатенация двух строк результат+. Преобразование строк подробно указывается в описание строки конкатенация + оператор.
и
Если только одно выражение операнда type String, тогда преобразование строки выполняется на другом операнде вывести строку во время выполнения. результатом является ссылка на строку объект (вновь созданный, если только выражение - постоянная времени компиляции выражение (§15.28)), то есть конкатенация двух операндов строки. Персонажи левый операнд предшествует символы правого операнда в вновь созданной строке. Если операнд типа String равен null, тогда строка "null" используется вместо этот операнд.
Вторая строка преобразуется в следующий код:
s = (new StringBuilder()).append((String)null).append("hello").toString();
Прикладные методы могут обрабатывать аргументы null
.
Вы не используете "null", и поэтому вы не получите исключения. Если вы хотите NullPointer, просто сделайте
String s = null;
s = s.toString() + "hello";
И я думаю, что вы хотите сделать:
String s = "";
s = s + "hello";
Это поведение, указанное в методе Java API String.valueOf(Object)
. Когда вы выполняете конкатенацию, valueOf
используется для получения представления String
. Существует специальный случай, если Object null
, и в этом случае используется строка "null"
.
public static String valueOf(Object obj)
Возвращает строковое представление аргумента Object.
Параметры: obj - объект.
Возврат:
если аргумент равен null, тогда строка равна "null"; в противном случае возвращается значение obj.toString().