Связано с интернетом String
public static void main(String[] args) {
String a = new String("lo").intern();
final String d = a.intern();
String b = "lo";
final String e = "lo";
String c = "Hello";
System.out.println(b==a);//true
System.out.println(d==a);//true
System.out.println(e==a);//true
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
System.out.println(c=="Hel"+e); //this is true
}
В результате получается
true
true
true
false
false
false
true
Выражение e==a
истинно, подразумевает ту же ссылку. Итак, почему последнее выражение истинно, но четвертое - последнее, т.е. c== "Hel"+a
- false?
Ответы
Ответ 1
Выражение
"Hel" + a
Не является постоянной времени компиляции. Собственно, он компилируется в:
new StringBuilder().append("Hel").append(a).toString()
(или аналогичный), который создает новый объект String во время выполнения.
Однако, поскольку e
является окончательным, компилятор может определить, что конкатенация значений "Hel"
и e
является постоянным значением и, таким образом, ставляет его.
Ответ 2
все эти строки вычисляются во время выполнения, поэтому они различаются
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
этот вычисляется во время компиляции, так как e является окончательным:
System.out.println(c=="Hel"+e); //this is true
если вы измените код на это:
System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
System.out.println(c==("Hel"+d).intern()); //why is this false?
System.out.println(c==("Hel"+b).intern()); //why is this false?
все они будут выдавать true
Ответ 3
Компилятор Java (javac
) переводит ваш код в Java в байтовый код, который выполняется JVM.
Он также выполняет некоторые оптимизации для вас. Вы можете проверить сгенерированный байт-код с помощью утилиты javap
с параметром -c
Конкатенация с окончательной строкой
c==a
истинно, потому что c
- final
Вот код байта для этого фрагмента (только последнее сравнение):
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String Hello
2: astore_2
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_2
7: ldc #2; //String Hello
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
}
Как вы видите, компилятор java объединил "Hel" с "lo" и просто сравнил два строковых словаря "Hello". Java ставит строковые литералы по умолчанию - почему он возвращает true
Конкатенация с нестрочной строкой
Если вы объединяете строковый литерал с нестрочной переменной String, код байта будет отличаться:
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String lo
2: astore_1
3: ldc #3; //String Hello
5: astore_2
6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_2
10: new #5; //class java/lang/StringBuilder
13: dup
14: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
17: ldc #7; //String Hel
19: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: if_acmpne 36
32: iconst_1
33: goto 37
36: iconst_0
37: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
40: return
}
Здесь мы сравниваем результат метода java/lang/StringBuilder.toString:()Ljava/lang/String;
, который явно возвращает другой объект - он равен "Hello" по значению, но не по ссылке
Более подробную информацию о сравнении строк в этом fooobar.com/questions/21/...
Ответ 4
Даже если вы используете метод intern()
, вы должны помнить, что ==
сравнивается по ссылке, а не по значению.
Итак, в случаях
System.out.println(c=="Hel"+a);
System.out.println(c=="Hel"+d);
System.out.println(c=="Hel"+b);
"Hel" + a
или "Hel" + d
или "Hel" + b
будет иметь новую ссылку в памяти, которая не равна значению c
.
в последнем случае, поскольку строковое значение является окончательным, оценка выполняется во время компиляции, а не во время выполнения, поскольку она никогда не изменится. Также, если вы думаете, когда вы определяете строковый литерал, Java внутренне ставит их в очередь.