Использование конструктора String (String) в Java

Я читал в статьях и книгах, что использование String s = new String("..."); следует избегать почти все время. Я понимаю, почему это так, но есть ли смысл вообще использовать конструктор String (String)? Я не думаю, что есть, и не вижу никаких доказательств в противном случае, но мне интересно, знает ли кто-либо в сообществе SO об использовании.

Ответ 1

Это хорошая статья: Конструктор String, который считается бесполезным, оказывается полезным в конце концов!

Оказывается, этот конструктор действительно может быть полезен, по крайней мере, в одном случае. Если вы когда-либо заглядывали в исходный код String, вы увидите, что у него есть не только поля для значения массива char и количество символов, но и смещение к началу строки. Это значит, что строки могут совместно использовать значение массива char с другими строками, как правило, это результат вызова одного из методов substring(). Java была известна за это в jwz 'Java rant из лет назад:

Единственная причина для этих накладных расходов заключается в том, что String.substring() может возвращать строки, которые имеют один и тот же массив значений. Выполнение этого за счет добавления 8 байтов к каждому объекту String не является чистой экономией...

Сохранение байтов в сторону, если у вас есть такой код:

// imagine a multi-megabyte string here  
String s = "0123456789012345678901234567890123456789";  
String s2 = s.substring(0, 1);  
s = null;

Теперь у вас будет String s2, который, хотя и представляет собой односимвольную строку, содержит ссылку на гигантский массив char, созданный в String s. Это означает, что массив не будет собирать мусор, хотя мы явно вытеснили строку s!

Исправление для этого - использовать наш ранее упоминавшийся "бесполезный" конструктор String следующим образом:

String s2 = new String(s.substring(0, 1));  

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

Наконец, Kat Marsen делает эти баллы,

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

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

Ответ 2

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

Ответ 3

Просто чтобы развернуть Douglas answer *, я могу привести пример того, где я его использовал. Подумайте о чтении словарного файла с тысячами строк, каждое из которых - всего лишь одно слово. Самый простой способ прочитать это - использовать BufferedReader.readLine().

К сожалению, readLine() выделяет буфер по умолчанию 80 символов по умолчанию в качестве ожидаемой длины строки. Это означает, что обычно это может избежать бессмысленного копирования - и немного потерянной памяти обычно не так уж плохо. Однако, если вы загружаете словарь коротких слов в течение всего срока действия приложения, вы получаете огромное количество памяти, которая постоянно теряется. Мое "маленькое приложение" всасывало гораздо больше памяти, чем следовало делать.

Решение заключалось в том, чтобы изменить это:

String word = reader.readLine();

в это:

String word = new String(reader.readLine());

... с комментариями, конечно!

* Я не помню, работал ли я с Дугласом, когда это произошло, или просто случайно, что он ответил на этот конкретный вопрос.

Ответ 4

Конструктор в значительной степени избыточен и не рекомендуется для общих целей. Строковый конструктор с аргументом String редко используется, кроме как для создания независимой копии существующей строковой переменной. В основном использовать его для "уточнения" вашего кода. Не меньше.

Ответ 5

из javadoc

/**
 * Initializes a newly created {@code String} object so that it represents
 * the same sequence of characters as the argument; in other words, the
 * newly created string is a copy of the argument string. Unless an
 * explicit copy of {@code original} is needed, use of this constructor is
 * unnecessary since Strings are immutable.
 *
 * @param  original
 *         A {@code String}
 */
public String(String original){.....}

Ответ 6

Вы используете его, если вам нужна копия исходной строки, если вы не хотите указывать дескриптор исходной строки. Но поскольку строки неизменяемы, я не вижу случая использования fot this;)