TL; DR - ваше замешательство вызывает модель памяти Java для строк, а именно области Heap и String Constant Pool области память.
Глубокое погружение в модель памяти String
Мотивация дизайна
В Java, String , вероятно, наиболее часто используемый объект. Из-за этого Java поддерживает объекты String со специальной стратегией проектирования памяти, удерживая их либо в Heap , либо в изолированном подмножестве кучи, называемом String Constant Pool , либо в оба.
Пул констант String - это специальное пространство в памяти Heap , в котором хранятся строковые объекты уникальных "literal value"
s. Каждый раз, когда вы создаете String с его буквальным значением, JVM сначала проверяет, доступен ли объект с таким же значением в пуле String, и если он есть, возвращается ссылка на тот же объект, если нет - новый объект выделены в пуле констант , и то же самое происходит для всех других созданий литералов String снова и снова.
Причина, почему наличие пула констант - хорошая идея , является семантикой самой фразы, потому что в ней хранятся объекты constant и immutable String, и, как вы видите, это отличная идея для тех случаев, когда вы можете создать много Строковые объекты с одинаковым буквальным содержанием - во всех этих случаях каждый раз будет ссылаться только один объект для одного "literal value"
, а новые объекты не будут созданы для существующего строкового литерала object.
Обратите внимание, что это возможно только потому, что String неизменяема по определению. Также обратите внимание, что пул строк, который изначально пуст, поддерживается классом String в частном порядке.
Где Java размещает объекты String?
А вот и начинается самое интересное. Важно помнить, что всякий раз, когда вы создаете объект String с помощью инструкции new String()
, вы заставляете Java разместить новый объект в Heap ; однако, если вы создаете объект String с "string literal"
, он выделяется в String Constant Pool . Как мы уже говорили, String Constant Pool существует в основном для уменьшения использования памяти и улучшения повторного использования существующих String объектов в памяти.
Итак, если вы напишете:
String s1 = "a";
String s2 = "a";
String s3 = new String("a");
- Строковый объект будет создан в String Constant Pool , а ссылка на этот объект будет сохранена в переменной
s1
; - Будет выполнен поиск пула строковых констант , а из-за в пуле найден объект с таким же буквальным значением (
"a"
), будет возвращена ссылка на тот же объект; - String объект будет явно создан в области Heap , и ссылка будет возвращена и сохранена в переменной
s3
.
Internig Strings
Если вы wi sh перемещаете объект String, созданный с помощью оператора new
, в пул констант String , вы можете вызвать метод "your_string_text".intern();
и один из два будет :
- , если пул уже содержит ins строку, равную этому объекту String, как определено методом equals (Object), тогда будет возвращена строка из пула;
- в противном случае этот объект String будет добавлен в пул и ссылка на него Будет возвращен строковый объект.
Что происходит в вашем коде?
String s1 = "a";
String s2 = "a";
Оба s1 и s2 будут указывать на один и тот же адрес в пуле строк, и будет только один объект со значением «a».
Верно. Первоначально будет создан объект String, который будет помещен в String Constant Pool . После этого, поскольку уже существует String со значением "a"
, новый объект не будет создан для s2
, а ссылка, хранящаяся в s1
, будет аналогичным образом сохранена в s2
.
Теперь давайте, наконец, посмотрим на ваш вопрос:
String s1 = "a"; //allocated in the String Constant Pool
s1 = s1.concat("b"); //contact() returns a new String object, allocated in the Heap
String s2 = "ab";//"ab" still does NOT exist in the String Constant Pool, and it gets allocated there
System.out.println(s1 == s2); //returns false, because one object is in the Heap, and another is in the String Constant Pool, and as there already exists the object in the pool, with the same value, existing object will be returned by `intern()`.
Если вы, однако, выполните
System.out.println(s1.intern() == s2);
, это вернет true
, и я надеюсь, Теперь вы понимаете - почему. Поскольку intern()
переместит объект, на который есть ссылка через s1
, из Heap в String Constant Pool .