Где строковые объекты при создании с использованием методов tostring, хранящихся в памяти на Java?
Я выполнял одно задание, и у меня был следующий вопрос.
Где хранятся в памяти строковые объекты, созданные с помощью метода toString()
?
String a = Integer.toString(10);
- В постоянном пуле
- В куче (область нового объекта оператора)
Ответы
Ответ 1
Это был странный (я бы сказал, плохой) вопрос о том, что вас спросили, потому что ответ на этот вопрос зависит от реализации JDK. Эта реализация может измениться, и это не то, о чем обычно должен знать нормальный человек, потому что, чтобы точно узнать, вам нужно спросить исполнителей или прочитать их исходный код. Кроме того, с Java 7 пул строк (который я подразумеваю под термином "постоянный пул" ) находится в куче. Так что даже если он в пуле строк, он все еще находится в куче.
В настоящее время (OpenJDK 8u40-b25), что String
будет новым объектом, созданным в кучевой памяти:
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
Поскольку вы передаете 10
, а не Integer.MIN_VALUE
, создается новый объект String
. Содержимое этой строки представляет собой массив char
, который был создан с помощью new
, поэтому существует в куче. intern()
не вызывается на него, поэтому он не помещается в пул строк.
Вы можете проверить, что это поведение, которое вы получаете, используя тот факт, что ==
с String
проверяет, являются ли они одним и тем же объектом, а не тем же значением. Ниже будет указано значение False
, поскольку статический метод Integer.toString()
создал новый объект String
в куче каждый раз, когда он был вызван:
Integer.toString(10) == Integer.toString(10)
Если бы они были интернированы в пул строк, они были бы одним и тем же объектом (потому что точка интернирования - только один объект на строку). Следующее оценивается как True
:
Integer.toString(10).intern() == Integer.toString(10).intern()
Обратите внимание, что это ответ специально для статического метода Integer.toString()
, а не для всех методов toString()
. Boolean.toString()
, например, возвращает строки из пула строк.
Ответ 2
Все они входят в память кучи. Только строковые литералы и интернированные строки входят в пул констант String.
Единственными исключениями являются такие классы, как String
:
public String toString() {
return this;
}
Он просто возвращает текущую строку (если она находится в куче, она возвращается из кучи/если она находится в пуле строковых констант, она возвращается из пула строковых констант)
Примечание. Если toString()
НЕ переопределено для возврата строкового литерала явно, представление String (ClassName @hexValueOfHashCode) всегда создается в куче.
Ответ 3
Это зависит от реализации метода toString()
, который вы вызываете.
Метод toString()
создает объект String
, поэтому в зависимости от того, как он это делает (и является ли он интернетом строку или нет), возвращаемый String
будет в пуле строк или нет.
Обратите внимание, что toString()
- это просто метод, подобный любому другому методу. Нет никакой магии, которая обрабатывает возвращаемое значение метода toString()
любым специальным способом. (Строки, возвращаемые toString()
, например, не интернированы автоматически). Он работает точно так же, как и с любым другим методом, который возвращает String
.
Ответ 4
Вопрос, который вам дал, является ошибочным.
Прежде всего, два варианта: (1) возврат строки, которая в пуле констант и (2) возврат вновь созданной строки, не являются взаимоисключающими, поскольку метод может создать новую строку, но затем intern()
, чтобы получить его в постоянном пуле.
Во-вторых, нет особых требований к тому, как методы toString()
идут на поставку своих строк в целом. Это полностью зависит от конкретной реализации конкретного метода toString()
. Вы не можете обобщать и говорить, что все они делают определенную вещь.
-
Некоторые методы могут возвращать new String(...)
для каждого вызова (что было бы подходящим, скажем, a StringBuilder
).
-
Некоторые методы всегда могут возвращать экземпляр строки из небольшого набора фиксированных возможностей, и эти фиксированные возможности могут также находиться в постоянном пуле (который подходит для класса Boolean
или для констант перечисления).
-
Некоторые методы могут сочетать вещи. Integer.toString(int)
может использовать набор предопределенных констант для небольших общих значений, но возвращать новые строки кучи для получения более неясных значений. Или он может генерировать и кэшировать строки по требованию, так что Integer.toString(10)
может возвращать новую кучу в первый раз, но возвращать одну и ту же строку кучи при последующих вызовах; и в этом случае, если вызывающий объект Integer.toString
где-то .intern()
имеет свои возвращаемые значения, тогда экземпляры класса Integer
по требованию кэширования могут также попасть в постоянный пул.
Поведение также может варьироваться в зависимости от версии JVM или версии JVM или времени выполнения, которые передаются ему.
К конкретному вопросу о том, что в настоящее время делает Integer.toString(int)
в OpenJDK 8, проверить источник:
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
Оказывается, он возвращает строковый литерал (который будет в пуле констант) для Integer.MIN_VALUE
, но новая строка кучи для каждого другого значения. (Это может показаться странным, но обычно для функций с номерами в строке на многих языках программирования делается исключение для значения min таким образом, поскольку two дополнение представления целых чисел максимальное значение на 1 меньше абсолютного значения min (например, диапазон от -2,147,483,648 до +2,147,483,647), что означает, что минимальное значение является единственным отрицательным значением, которое вы не можете переключить на положительное и затем обработать, используя тот же общий код цикла, что и для положительных значений.)
Третья проблема заключается в том, что ответ вряд ли имеет значение. Только если вы обнаружите, что реализация метода toString()
не работает или имеет неудовлетворительную производительность, тогда вы можете исследовать причину, но в противном случае, пока она работает и работает эффективно, почему кому-то нужно, как она кэширует строки или кэширует их или нет? Java-новички вынуждены слишком беспокоиться о деталях пустого пула константных строк, что является неудачным побочным эффектом плохого решения Java, чтобы не иметь ==
вызов .equals()
для объектов, что делает поведение константы пул более заметен.
Если вам нужна строка, определенная в пуле констант, вы можете ставить ее самостоятельно или записать в виде строкового литерала в источнике. В противном случае у вас нет гарантии, находится ли он или нет в постоянном пуле, но также не нуждается в такой гарантии.
На основе реализации Integer.toString(int)
они, вероятно, ищут ответ 2 ( "на куче" ), но это неверный ответ на очень ошибочный вопрос.
Ответ 5
Я считаю, что это должно зависеть от реализации. Но по умолчанию toString из java.lang.Object
и много других реализаций toString
объектов возвращают только строковые литералы. Поэтому я могу сказать вам, что они находятся в строчном постоянном пуле, потому что по умолчанию они interned
, и все интернированные строки будут сохранены в пуле константных строк.
Пример 1
public String toString() {
return "my test string"; // will be in string constant pool
}
Пример 2
public String toString() {
String s1 = new String("my test string");
return s1; // s1 will be in heap
}
Конечно, мне не нужно говорить вам, что s1.intern()
поместит строку примера в строковый пул констант, если он еще не доступен
Ответ 6
В классе обертки Integer, после того как данный int проанализирован на char, он вернет новый объект String.
return new String(buf, true);
это создаст 1 строковый объект в памяти кучи.
Контрольная переменная "a" указывает на объект в куче (нормальная память).
Но помните, что
String str = new String("abc");
создаст 2 объекта, один в куче и другой в пуле строк.
Константы времени компиляции Выражения типа String всегда интернированы.
Ответ 7
Он зависит от реализации. Однако по умолчанию строка переходит в пул строк.
Случай 1:
public String toString() {
return "Constant Pool"; // String constant pool
}
Случай 2:
public String toString() {
String string2 = new String("Heap String");
return string2; // in heap
}
Оба выражения дают вам объект String
, но между ними существует тонкая разница.
- Когда вы создаете
String
с помощью оператора new()
, он всегда создает новый объект в куче памяти.
- Если вы создаете объект, используя синтаксис строкового литерала, он может вернуть существующий объект из String pool, если он уже существует. В противном случае он создаст новый строковый объект и добавит пул строк для последующего повторного использования.
Когда вы создаете строку с использованием строкового литерала, она автоматически вызывает метод intern()
, чтобы поместить этот объект в String pool (если он уже не был в пуле). В случае нового он не выполняется автоматически, пока на этот объект не будет вызван метод intern()
.