Как Java реализует шаблон в наилегчайшем весе для строки под капотом?

Если у Вас есть два экземпляра Строки, и они равны в Java, они совместно используют ту же память. Как это реализовано под капотом?

Править: Мое приложение использует большое количество Строковых объектов, многие из которых идентичны. Что лучший способ состоит в том, чтобы использовать пул Строковой константы Java, чтобы не создавать пользовательскую реализацию в наилегчайшем весе?

17
задан Dan 26 May 2010 в 03:16
поделиться

7 ответов

Посмотрите исходный код java.lang.String (исходный код всего java api является частью JDK).

Подводя итог: String является оболочкой для подпоследовательности char [] . Эта поддержка char [] никогда не изменяется. Это не достигается ни утечкой, ни захватом этого char [] вне класса String . Однако несколько строк могут совместно использовать один и тот же char [] (см. Реализацию String.substring ).

Существует также механизм интернирования, как объясняется в других ответах.

7
ответ дан 30 November 2019 в 12:13
поделиться

Если у вас есть два экземпляра String, и они равны, в Java они будут использовать одну и ту же память

На самом деле это не на 100% верно.

Эта статья в блоге хорошо объясняет, почему это так, и что такое пул констант String.

12
ответ дан 30 November 2019 в 12:13
поделиться

Две вещи, с которыми нужно быть осторожным:

  1. Не используйте конструктор new String("abc"), используйте только литерал "abc".
  2. Научитесь использовать метод intern() в классе String. Особенно при конкатенации строк или при преобразовании массива символов/байтового массива/etc в строку.

intern() всегда возвращает объединенные строки.

1
ответ дан 30 November 2019 в 12:13
поделиться

Строковые литералы интернированы в Java, поэтому на самом деле существует только один объект String с несколькими ссылками (когда они равны, что не всегда так). См. Статью java.net Все о intern () для получения более подробной информации.

Также есть хороший пример / объяснение в разделе 3.10.5 Строковые литералы JLS, в котором говорится о том, когда строки интернированы и когда они будут отличаться.

6
ответ дан 30 November 2019 в 12:13
поделиться

Это не обязательно правда. Пример:

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true

но:

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false

Теперь вторая форма не приветствуется. Некоторые (включая меня) думают, что String не должно даже иметь открытого конструктора. Лучшая версия вышеизложенного:

String s1 = new String("hello").intern();
String s2 = new String("hello").intern();
System.out.println(s1 == s2); // true

Очевидно, вам не нужно делать это для константы String . Это показательно.

Важным моментом здесь является то, что если вы передали String или получили его из функции, вы не можете полагаться на то, что String является каноническим ]. канонический объект удовлетворяет этому равенству:

a.equals(b) == b.equals(a) == (a == b)

для не нулевых экземпляров a , b, данного Класс .

4
ответ дан 30 November 2019 в 12:13
поделиться

Чтобы ответить на ваш отредактированный вопрос, в Sun JVM есть опция -XX:+StringCache, которая, по моим наблюдениям, может значительно уменьшить объем памяти приложения с большим количеством строк.

В противном случае, у вас есть возможность интернализации строк, но я был бы осторожен в этом вопросе. Строки, которые очень велики и на которые больше не ссылаются, будут использовать память в течение всей жизни JVM.

Редактировать (в ответ на комментарий): Я впервые узнал об опции StringCache из здесь:

-XX:+StringCache Enables caching of commonly allocated strings.

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

3
ответ дан 30 November 2019 в 12:13
поделиться

Если ваши одинаковые строки происходят из фиксированного набора возможных значений, то безопасное для типов перечисление - это то, что вам нужно. Это не только сократит количество строк, но и сделает приложение более надежным. Все ваше приложение будет знать, что у этой строки есть семантика, привязанная к ней, возможно, даже некоторые удобные методы.

Мои любимые оптимизации - это те, которые можно защитить как делающие код лучше, а не просто быстрее. И 9 раз из 10 замена String на конкретный тип приводит к более корректному и самодокументированному коду.

0
ответ дан 30 November 2019 в 12:13
поделиться
Другие вопросы по тегам:

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