Время создания строк в Java - PullRequest
8 голосов
/ 12 августа 2010

Я пишу приложение для устройств J2ME и в значительной степени беспокоюсь о ненужном создании строк.Поскольку работа со строками является встроенной, т. Е. Нет необходимости создавать их явно, я не уверен, правильно ли я понимаю.

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

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

Ответы [ 6 ]

4 голосов
/ 12 августа 2010

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

return "foo";

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

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

Теперь, еслиВаш код на самом деле выглядит примерно так:

return "foo" + new Date();

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

2 голосов
/ 12 августа 2010

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

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

  • Когда приложение вызывает new String(...), когда оно оценивает выражение конкатенации 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 вызывает создание рядаСтроки.)

1 голос
/ 12 августа 2010

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

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

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

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


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

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

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

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

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

( на уровне байтового кода , поскольку компиляторы могут оптимизировать конкатенации литералов String в один литерал, например: выражение "one"+"two" будет скомпилировано в "onetwo")

1 голос
/ 12 августа 2010
  1. правый
  2. правый
0 голосов
/ 12 августа 2010

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

0 голосов
/ 12 августа 2010

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

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

  1. Да, будет создана только возвращаемая строка
  2. Да, только когда генерируется исключение, эта строка будет создана
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...