Распределение памяти при создании новой строки как литерал / новый объект - PullRequest
3 голосов
/ 16 марта 2020

Код:

String s1 = "Hello";
String s2 = new String("Hello");

Field declaredField = String.class.getDeclaredField("value");
declaredField.setAccessible(true);

byte[] arr1 = (byte[])declaredField.get(s1);
byte[] arr2 = (byte[])declaredField.get(s2);

Теперь s1 == s2 = False, arr1 == arr2 = True.

Мой вопрос заключается в том, как объекты хранятся в памяти.

Первая строка создает новый объект типа String в пуле. Вторая строка создает его в куче как обычный объект

Но базовый массив byte [] такой же. Это заставляет меня задуматься, так или иначе, JVM делает эту проверку, если такой существующий byte [] уже существует, и указывает все ссылки на один и тот же массив. Означает ли это, что базовый массив кэшируется в пуле, независимо от того, используем ли мы буквальное или новое ключевое слово?

Таким образом, s = "что-то" создает новый объект типа String в пуле вместе с базовым массивом, содержащим data - который также создается в пуле.

s = new String("something") -> создает объект типа String в куче, но базовый массив все еще хранится в пуле / если он уже существует, ссылка просто создается.

Правильно ли мое понимание?

Примечание: это не вопрос о том, где хранится постоянный пул, как работает интер, сколько объектов создано или как используется другая техника создания / использования Стажер влияет на результаты ==.

1 Ответ

2 голосов
/ 16 марта 2020

Какую java версию вы используете? Я проверяю это на 11 jdk и тип String.value это char []. Все последующие слова основаны на версии 11 JDK.

Причиной такого поведения является конструктор String.

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

Как видите, поле value скопировано из original Строковый объект. Поскольку вы используете "Hello" для new String(...) аргумента, "Hello" получается из пула String и передается в конструктор, где поле value копируется в новый объект String.

Вы можете немного измените свой код для достижения ожидаемого поведения:

String s1 = "Hello";
String s2 = new String("Hell") + "o";
Field declaredField = String.class.getDeclaredField("value");
declaredField.setAccessible(true);
char[] arr1 = (char[])declaredField.get(s1);
char[] arr2 = (char[])declaredField.get(s2);
assert arr1 != arr2;
assert s1.equals(s2);
...