Время строкового создания в Java

Я пишу приложение для устройств J2ME и в значительной степени забочусь о ненужном Строковом создании. Как работающий со Строками встроено, т.е. не необходимо создать их явно, я не уверен, понимаю ли я это правильный.

Например, возврат Строки (только при помощи двойных кавычек) создает строку, когда это возвращается, т.е. если у меня есть несколько операторов возврата, возвращая различные Строки, только один из быть созданным. Это правильно?

Также при использовании Строк для печати сообщений за Исключениями, эти Строки никогда не создаются, если Исключение не становится брошенным, правильно?

Извините, что побеспокоил Вас таким вопросом о новичке.

8
задан Albus Dumbledore 12 August 2010 в 09:11
поделиться

6 ответов

Я совершенно не уверен в ответах, которые вы получили до сих пор. Если вы просто возвращает строковый литерал, например

return "foo";

, то эти значения вставляются в файл класса. JVM гарантирует, что когда-либо будет создан только один экземпляр этой строки (из литерала), но я не думаю, что есть какая-либо гарантия, что она не создаст строки для всех констант в классе, когда сам класс загружается.

Опять же, поскольку строка будет создана только один раз (на строковую константу), это вряд ли будет проблемой.

Теперь, если ваш код на самом деле больше похож на этот:

return "foo" + new Date();

, тогда этот является динамически создающим строку, но она будет создана только в том случае, если действительно сработает оператор return.

4
ответ дан 5 December 2019 в 20:11
поделиться
  1. Правый
  2. Правый
1
ответ дан 5 December 2019 в 20:11
поделиться

Строки (и другие объекты) создаются только тогда, когда вы их вызываете.

Итак, чтобы ответить на ваши вопросы:

  1. Да, будет создана только возвращенная строка
  2. Да, эта строка будет создана только при возникновении исключения
0
ответ дан 5 December 2019 в 20:11
поделиться

Ответ немного сложнее, чем предполагают некоторые другие ответы.

  • Значение String, соответствующее строковому литералу в исходном коде, создается один раз при загрузке класса. Кроме того, эти Строки автоматически «интернируются», что означает, что если один и тот же литерал появляется более чем в одном месте в любом классе , будет сохранена только одна копия Строки. (Любые другие копии, , если они были созданы , получат сборщик мусора.)

  • Когда приложение вызывает new String (...) , когда оно оценивает выражение конкатенации строк ( т.е. оператор + ), или когда он вызывает один из многих библиотечных методов, которые создают строки под капотом, будет создана новая строка.

Итак, чтобы ответить на ваши вопросы:

1 - Следующее на самом деле не будет создавать строку вообще. Скорее, он вернет строку, которая была создана при загрузке класса:

        return "some string";

2 - Следующее будет создавать две строки. Сначала он вызовет someObject.toString (), а затем объединит его с литералом, чтобы получить еще одну строку.

        return "The answer is :" + someObject;

3 - Следующие строки не будут создавать строку; см. 1.

        throw new Exception("Some message");

4 - При выполнении будут созданы две строки; см. 2.

        throw new Exception(someObject + "is wrong");

(Фактически, 3 и 4 затушевывают тот факт, что создание исключения приводит к захвату деталей стека вызовов текущего потока, и эти детали включают имя метода, имя класса и имя файла для каждого кадра. не указывается, когда фактически создаются строки, представляющие эти вещи, или интернированы ли они.Таким образом, возможно , что действие по созданию объекта Exception запускает создание ряда строк.)

2
ответ дан 5 December 2019 в 20:11
поделиться

Основная концепция здесь заключается в том, что выделение кучи (то, что вы говорите создание) для любой строки или, в более общих терминах, для любого объекта не происходит до тех пор, пока ваш логический поток не заставит интерпретатор выполнить эту строку скомпилированного кода.

0
ответ дан 5 December 2019 в 20:11
поделиться

Да. Если выражение, которое создает экземпляр либо путем вызова конструктора, либо (для строк), оценивающего литерал, не выполняется, то ничего не создается.

И, кроме того, компиляторы проводят некоторую оптимизацию. Строковые объекты, основанные на строковых литералах, будут созданы только один раз и впоследствии интернированы. как здесь:

public String getHello() {
  return "Hello";  
}

public void test() {
  String s = getHello();  // String object created
  String t = getHello();  // no new String object created
}


JVMS имеет другое «мнение»:

Новый экземпляр класса может быть неявно создан в следующих ситуациях:

  • Загрузка класса или интерфейса, содержащего строку literal может создать новый объект String (§2.4.8) для представления этого литерала. Этого может не произойти, если объект String уже был создан для представления предыдущего вхождения этого литерала или если метод String.intern был вызван для объекта String, представляющего ту же строку, что и литерал.

Итак, приведенный выше пример неверен (я узнаю что-то новое каждый день). ВМ проверяет во время загрузки класса, нужно ли создать «Hello» (и создаст экземпляр String, если он еще не существует).

Итак, теперь я понимаю, что виртуальная машина создает экземпляр String для каждого уникального строкового литерала (на уровне байтового кода!), Независимо от того, используется он или нет.

( на уровне байтового кода , потому что компиляторы могут оптимизировать конкатенацию строковых литералов в один литерал, например: выражение «один» + «два» будет скомпилировано в "onetwo" )

1
ответ дан 5 December 2019 в 20:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: