По сути этот вопрос продолжает другой вопрос.
Во многих статьях говорится, что при создании строк без new
через литерал строка попадает в пул строк. В противном случае необходим метод intern
. Как тогда объяснить поведение ниже ?
String s2 = "hello";
String s1 = "hello";
System.out.println(s1 == s2); // true
System.out.println("hel" + "lo" == "hello"); // true
s1 = "hello";
s2 = "hel";
String s3 = "lo";
System.out.println(s1 == s2 + s3); // false
System.out.println(s2 + s3 == "hel" + "lo"); //false
Если в последнем случае s2
ссылается туда же куда и литерал "hel", и с s3
такая же история, то почему "hel" + "lo"
не равно (по ссылке) s2 + s3
?
Строка может попасть в пул констант в двух случаях:
Компилятор проходит по всем строкам в исходном коде и добавляет их в пул констант. Если в коде есть какие-то места, в которых нужны вычисления и компилятор может их произвести, то он делает это. В Вашем примере это System.out.println("hel" + "lo" == "hello");
. Сконкатенировал "hel" + "lo"
и положил в пул.
Описание метода (ссылка на документацию). Здесь надо обязательно указать границы применения данного способа. Данный методы выглядит очень заманчиво: "мы можем сократить использование памяти, и производительность в програме!! Это громадная оптимизация!!"
Если мне не верите, то Алексею Шипилеву должны поверить (про intern с 32 минуты).
Строка попадет в пул строк только после вызова метода intern класса String.
Детально про строковые литералы из спецификации на английском
По поводу "hel" + "lo" - это строковая константа
Возьмем класс
public static void main(String[] args) {
String s2 = "hel";
String s3 = "lo";
System.out.println(s2 + s3 == "hel" + "lo");
}
Скомпилируем и посмотрим его декомпилятором
public static void main(String[] args) {
String s2 = "hel";
String s3 = "lo";
System.out.println(s2 + s3 == "hello");
}
Компилятор собрал "hel" + "lo" в одну строку, что бы доказать это, посмотрим байткод:
public static main([Ljava/lang/String;)V
L0
LINENUMBER 6 L0
LDC "hel"
ASTORE 1
L1
LINENUMBER 7 L1
LDC "lo"
ASTORE 2
L2
LINENUMBER 9 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
LDC "hello"
IF_ACMPNE L3
ICONST_1
GOTO L4
L3
FRAME FULL [[Ljava/lang/String; java/lang/String java/lang/String] [java/io/PrintStream]
ICONST_0
L4
FRAME FULL [[Ljava/lang/String; java/lang/String java/lang/String] [java/io/PrintStream I]
INVOKEVIRTUAL java/io/PrintStream.println (Z)V
L5
LINENUMBER 10 L5
RETURN
L6
LOCALVARIABLE args [Ljava/lang/String; L0 L6 0
LOCALVARIABLE s2 Ljava/lang/String; L1 L6 1
LOCALVARIABLE s3 Ljava/lang/String; L2 L6 2
MAXSTACK = 3
MAXLOCALS = 3
}
"hello" представлена константой, s2 + s3 собираются через StringBuilder и преобразуются в строку через toString(), соответственно это 2 разных объекта, и при сравнении указателей будет false
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
ЗдравствуйтеПишу неофициальный SDK для браузерной игры, который разработчики смогут встраивать в свой проект