Подтвердить что ты не робот

Где строковые объекты при создании с использованием методов tostring, хранящихся в памяти на Java?

Я выполнял одно задание, и у меня был следующий вопрос.

Где хранятся в памяти строковые объекты, созданные с помощью метода toString()?

String a = Integer.toString(10);
  • В постоянном пуле
  • В куче (область нового объекта оператора)
4b9b3361

Ответ 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().