Я думаю, что все программисты Java были обеспокоены этим новым вопросом String.Это очень частый вопрос Java-интервью, но, к сожалению, в Интернете есть разные мнения, и стандартного ответа нет. Некоторые люди говорят, что создается 1 объект, некоторые люди говорят, что создаются 2 объекта, а некоторые люди говорят, что могут быть созданы 1 или 2 объекта, но ни у кого нет никаких доказательств, чтобы убить другую сторону, что делает нас едоками дыни. оказались перед дилеммой, не зная, кому можно доверять.
Но сегодня Лао Ван осмелился поговорить на эту тему со всеми, и я, кстати, вынесу еще несколькосвидетельство.
Исходя из текущей ситуации, оnew String("xxx")Есть 3 ответа на количество созданных объектов:
- Некоторые говорят, что создается 1 объект;
- Некоторые говорят, что создаются 2 объекта;
- Некоторые говорят, что создаются 1 или 2 объекта.
Ключевым моментом разногласий, где есть несколько ответов, является «пул строковых констант»., некоторые говорят, что новый строковый метод создаст строковый объект в пуле констант, а некоторые говорят, что при использовании новой строки он не будет создавать объект в пуле строковых констант, а будет вызыватьintern()метод, он перейдет к пулу строковых констант для обнаружения и создания строки.
Итак, давайте сначала поговорим об этом «пуле строковых констант».
Пул строковых констант
Выделение строк, как и размещение других объектов, требует больших затрат времени и места. Если необходимо часто создавать большое количество строк, это сильно повлияет на производительность программы. Поэтому для повышения производительности и уменьшения накладных расходов памяти , JVM представляет концепцию пула строковых констант (таблица пула констант).
Пул строковых констант эквивалентен открытию пространства пула констант для строки, похожего на область буфера. Для напрямую назначенной строки (строка s="xxx") существующая строковая константа предпочтительно используется каждый раз при создании строки. Строка пула, если в пуле строковых констант нет связанной строки, строка будет сначала создана в пуле строковых констант, а затем адрес ссылки будет возвращен в переменную, как показано на следующем рисунке:
public class StringExample {
public static void main(String[] args) {
String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2);
}
}
Результат выполнения вышеуказанной программы:true, указывая, что переменная s1 и переменная s2 указывают на один и тот же адрес.
Здесь мы поговорим об изменениях пула строковых констант в разных версиях JDK.
Структура памяти постоянного пула
отПосле JDK 1.7 метапространство, замененное бессмертным поколением, переместило пул строковых констант из области методов в кучу Java..
Схема памяти JDK 1.7 показана ниже:
расшифровка ответа
Люди, которые думают, что новый способ создает 1 объект, думают, что новая строка просто создает объект в куче, только при использованииintern()Только после этого переходим к пулу констант, чтобы найти и создать строку.
Люди, которые думают, что новый способ создает 2 объекта, думают, что новая строка создает объект в куче, а также создает строку в пуле строковых констант.
Люди, которые думают, что в новом методе можно создать 1 или 2 объекта, думают, что new String сначала пойдет в пул констант, чтобы определить, есть ли такая строка, и если да, то только создаст строку в куче и указать на строку в пуле констант, если строка не существует в пуле констант, будут созданы два объекта, сначала создайте строку в пуле констант, а затем верните ссылку на объект в куче, как показано на следующий рисунок:
Фараон думает, что правильный ответ: создать 1 или 2 предмета.
техническая демонстрация
Чтобы решить звонок, звонок должен быть привязан.Возвращаясь к спорному моменту вопроса, будет ли новая строка создавать символы в постоянном пуле? Правильный вывод мы можем сделать, декомпилировав следующий код, код выглядит следующим образом:
public class StringExample {
public static void main(String[] args) {
String s1 = new String("javaer-wang");
String s2 = "wang-javaer";
String s3 = "wang-javaer";
}
}
Сначала мы используемjavac StringExample.javaСкомпилируем код, а затем используемjavap -v StringExampleПросмотрите скомпилированные результаты, соответствующая информация выглядит следующим образом:
Classfile /Users/admin/github/blog-example/blog-example/src/main/java/com/example/StringExample.class
Last modified 2020年4月16日; size 401 bytes
SHA-256 checksum 89833a7365ef2930ac1bc3d7b88dcc5162da4b98996eaac397940d8997c94d8e
Compiled from "StringExample.java"
public class com.example.StringExample
minor version: 0
major version: 58
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #16 // com/example/StringExample
super_class: #2 // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Class #8 // java/lang/String
#8 = Utf8 java/lang/String
#9 = String #10 // javaer-wang
#10 = Utf8 javaer-wang
#11 = Methodref #7.#12 // java/lang/String."<init>":(Ljava/lang/String;)V
#12 = NameAndType #5:#13 // "<init>":(Ljava/lang/String;)V
#13 = Utf8 (Ljava/lang/String;)V
#14 = String #15 // wang-javaer
#15 = Utf8 wang-javaer
#16 = Class #17 // com/example/StringExample
#17 = Utf8 com/example/StringExample
#18 = Utf8 Code
#19 = Utf8 LineNumberTable
#20 = Utf8 main
#21 = Utf8 ([Ljava/lang/String;)V
#22 = Utf8 SourceFile
#23 = Utf8 StringExample.java
{
public com.example.StringExample();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=1
0: new #7 // class java/lang/String
3: dup
4: ldc #9 // String javaer-wang
6: invokespecial #11 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: ldc #14 // String wang-javaer
12: astore_2
13: ldc #14 // String wang-javaer
15: astore_3
16: return
LineNumberTable:
line 5: 0
line 6: 10
line 7: 13
line 8: 16
}
SourceFile: "StringExample.java"
Примечание. Средой выполнения приведенного выше кода также является jdk1.8.0_101.
вConstant poolПредставляет пул строковых констант, мы нашли нас в пуле строковых констант во время компиляции строки.String s1 = new String("javaer-wang");Символ "javaer-wang", определенный в сообщении#10 = Utf8 javaer-wangВидно, чтоСтроки, созданные new во время компиляции, будут помещены в пул строковых констант во время компиляции., то есть новая строка
Метод сначала оценивает пул строковых констант. Если новой строки нет, то будут созданы 2 объекта. Если он уже существует, в куче будет создан только один объект, указывающий на строку в пуле строковых констант.
Итак, вопрос в том, является ли результат выполнения следующего кода истинным или ложным?
String s1 = new String("javaer-wang");
String s2 = new String("javaer-wang");
System.out.println(s1 == s2);
Поскольку new String создает строки в пуле констант, результат выполнения должен быть истинным. На самом деле это не так. Сравниваемые здесь переменные s1 и s2 являются адресами в куче. Поскольку адреса в куче разные, результат должен быть ложным, как показано на следующем рисунке:
public static void main(String[] args) {
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
String s4 = new String("Java");
System.out.println(s1 == s2);
System.out.println(s3 == s4);
}
Результат выполнения программы также ожидаем:
true false
расширить знания
Мы знаем, что String является final Modified, что означает, что его нельзя изменить, пока ему не будет присвоено значение. Однако в дополнение к оптимизации пула строковых констант компилятор также оптимизирует строки, которые могут быть подтверждены во время компиляции, например следующий код:
public static void main(String[] args) {
String s1 = "abc";
String s2 = "ab" + "c";
String s3 = "a" + "b" + "c";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
}
Согласно идее, что String нельзя изменить, s2 должен создать две строки «ab» и «c» в пуле строковых констант, а s3 создаст три строки, и результат их эталонного сравнения должен быть ложным, но на самом деле нет, все их результаты верны, что является заслугой оптимизации компилятора.
Так же мы используемjavac StringExample.javaСначала скомпилируйте код, а затем используйтеjavap -c StringExampleКоманда для просмотра скомпилированного кода выглядит следующим образом:
警告: 文件 ./StringExample.class 不包含类 StringExample
Compiled from "StringExample.java"
public class com.example.StringExample {
public com.example.StringExample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #7 // String abc
2: astore_1
3: ldc #7 // String abc
5: astore_2
6: ldc #7 // String abc
8: astore_3
9: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_1
13: aload_2
14: if_acmpne 21
17: iconst_1
18: goto 22
21: iconst_0
22: invokevirtual #15 // Method java/io/PrintStream.println:(Z)V
25: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_1
29: aload_3
30: if_acmpne 37
33: iconst_1
34: goto 38
37: iconst_0
38: invokevirtual #15 // Method java/io/PrintStream.println:(Z)V
41: return
}
Из кода 3 и 6 видно, что строки оптимизируются компилятором в строку «abc».
Суммировать
В этой статье мы проходимjavap -v XXXПосмотрите на скомпилированный код таким образом, что new String впервые создаст эту строку в пуле строковых констант, то есть создание строки с new может создать 1 или 2 объекта, если пул констант уже существует Эта строка только создаст переменную в куче и укажет на значение в пуле строковых констант.Если в пуле строковых констант нет соответствующего символа, строка будет создана первой, а ссылка на эту строку будет возвращена в кучу пространственная переменная. Мы также представили изменения пула строковых констант в JDK 1.7 и JDK 1.8 и оптимизацию компилятора для определения строки, надеясь помочь вам понять сравнение строк.
последние словаОригинальность непростая.В этой статье почти 3000 текстовых описаний и большое количество красивых картинок, на которые у автора ушло около 5 часов.Писать — это круто и помогает другим, автор надеется продолжить. Если вы найдете это полезным,Пожалуйста, не стесняйтесь нажимать лайк, спасибо.
Для получения более интересного контента, пожалуйста, обратите внимание на публичный аккаунт WeChat «Java Chinese Community».