Странный вывод в String в Java

Возможный дубликат:
объединение нулевых строк в Java

Пожалуйста, найдите ниже фрагмент кода

String str = null;
str = str + "hi";

System.out.println(str)

Вывод приведенного выше кода — nullhi.

Я думал, что вывод будет hi, поэтому был удивлен выводом и не смог найти причину этого.

Может кто-нибудь объяснить это.


person Anand    schedule 30.10.2012    source источник
comment
Мне потребовалось всего 5 секунд, чтобы получить ссылку на пост. Пожалуйста, используйте Google на регулярной основе.   -  person Rohit Jain    schedule 30.10.2012
comment
я не был уверен в тексте, который будет использоваться для поиска Google, поэтому разместил прямо здесь.   -  person Anand    schedule 30.10.2012


Ответы (6)


Из JLS.

http://docs.oracle.com/javase/specs/jls/se7/html/index.html

§15.18.1. Оператор конкатенации строк + (ссылка)

Если только одно выражение операнда имеет тип String, то преобразование строки (§5.1.11) выполняется для другого операнда, чтобы создать строку во время выполнения.

§5.1.11. Преобразование строк (ссылка)

Если ссылка пуста, она преобразуется в строку "null" (четыре символа ASCII n, u, l, l).

person jn1kk    schedule 30.10.2012

Это потому, что метод append. + преобразуется как операция добавления StringBuilder или StringBuffer.

public AbstractStringBuilder append(String str) {
if (str == null) str = "null";

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

Ниже приведен сгенерированный байт-код для вашей программы.

 0  aconst_null
 1  astore_1 [str]
 2  new java.lang.StringBuilder [16]
 5  dup
 6  aload_1 [str]
 7  invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [18]
10  invokespecial java.lang.StringBuilder(java.lang.String) [24]
13  ldc <String "hi"> [27]
15  invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [29]
18  invokevirtual java.lang.StringBuilder.toString() : java.lang.String [33]
21  astore_1 [str]
22  getstatic java.lang.System.out : java.io.PrintStream [37]
25  aload_1 [str]
26  invokevirtual java.io.PrintStream.println(java.lang.String) : void [43]
29  return

Таким образом, ваш код фактически преобразуется в append(null), а затем в append("hi"), поэтому вы получаете такой вывод.

Также это четко задокументировано в 15.18.1. String Concatenation Operator +

Реализация может выбрать выполнение преобразования и конкатенации за один шаг, чтобы избежать создания и последующего отбрасывания промежуточного объекта String. Чтобы повысить производительность повторяющейся конкатенации строк, компилятор Java может использовать класс StringBuffer или аналогичный метод для уменьшения количества промежуточных объектов String, создаваемых при вычислении выражения.

person Amit Deshpande    schedule 30.10.2012
comment
Это хорошие и забавные факты, но истинная причина наблюдения ОП заключается не в деталях реализации компилятора, а в JLS, который четко определяет семантику оператора конкатенации. - person Marko Topolnik; 30.10.2012
comment
@MarkoTopolnik Ваши комментарии всегда пополняют мои знания. Добавил такую ​​ссылку от JLS - person Amit Deshpande; 30.10.2012

null — это значение, которое выводится, если вы пытаетесь напечатать нулевую ссылку в java.

person Paul Morie    schedule 30.10.2012

Когда вы объединяете значения, которые не являются всеми строками, те, которые не являются строками, преобразуются, как если бы они были String.valueOf. String.valueOf(null) — это строка "null".

person Ian Roberts    schedule 30.10.2012
comment
Но str является строкой, так что это не объясняет. - person Marko Topolnik; 30.10.2012
comment
null не является строкой (на самом деле это не какой-либо объект). - person Ian Roberts; 30.10.2012
comment
Вы хотите сказать, что компилятор создает код, который динамически проверяет, следует ли использовать String.valueOf? Ваш вывод неверен: String.valueOf всегда вызывается для всех аргументов ссылочного типа для +. - person Marko Topolnik; 30.10.2012
comment
Честно говоря, я пытался описать эффект, а не механизм. - person Ian Roberts; 30.10.2012
comment
Описание эффекта также упрощается, если вы просто говорите, что все операнды преобразуются как бы String.valueOf. - person Marko Topolnik; 30.10.2012

Это было решение, которое создатели Java приняли на раннем этапе. Любое нулевое значение, объединенное со строкой, будет выводиться как null. Это имеет смысл, если вы представляете, что пытаетесь вывести сообщение журнала:

String personName = null;
System.out.println("Person name is: " + personName);

Результат:

Имя человека: null

Такое поведение может помочь вам при отладке, потому что вы знаете, что переменная на самом деле была нулевой (в отличие, например, от пустой строки).

Они могли бы просто выдать исключение, когда вы попытаетесь это сделать, но это привело бы к поломке многих вещей даже при выполнении чего-то вроде создания сообщения журнала или строки исключения.

Они также могли бы поступить так, как вы ожидали, и вывести нулевые значения в виде пустой строки. Это то, что делает платформа .NET. Но, в конце концов, это не то, что они решили сделать.

person StriplingWarrior    schedule 30.10.2012

В показанном вами примере вы объединяете строку null с hi, поэтому сгенерированный вывод будет
nullhi

String str = null;
str = str + "hi";

System.out.println(str);


as str=str+"hi "//shows one string is concatenating with the other

поэтому результат, который вы получаете, правильный.

person Abhishekkumar    schedule 30.10.2012