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




Вы используете его, если вам нужен копировать исходной строки, если вы не хотите давать дескриптор исходной строки. Но поскольку строки неизменяемы, я не вижу варианта использования для это;)
Если я правильно помню, единственный «полезный» случай - это когда исходная строка является частью гораздо большего массива поддержки. (например, создается как подстрока). Если вы хотите сохранить небольшую подстроку и собрать мусор в большом буфере, возможно, имеет смысл создать новую строку.
Нет, substring сохраняет указатель на исходный char [] вместо создания нового (так быстрее, но может привести к утечке памяти).
И в любом случае вы не всегда контролируете, что создает строку - см. Мой ответ для реального примера.
Лучшие (IMHO) реализации String отбрасывают смещение и длину. Тем не менее, вам, вероятно, придется иметь дело с не очень хорошими реализациями.
Это хорошая статья: Строковый конструктор, считающийся бесполезным, в конце концов оказывается полезным!
It turns out that this constructor can actually be useful in at least one circumstance. If you've ever peeked at the String source code, you'll have seen that it doesn't just have fields for the char array value and the count of characters, but also for the offset to the beginning of the String. This is so that Strings can share the char array value with other Strings, usually results from calling one of the substring() methods. Java was famously chastised for this in jwz' Java rant from years back:
The only reason for this overhead is so that String.substring() can return strings which share the same value array. Doing this at the cost of adding 8 bytes to each and every String object is not a net savings...
Byte savings aside, if you have some code like this:
// imagine a multi-megabyte string here String s = "0123456789012345678901234567890123456789"; String s2 = s.substring(0, 1); s = null;You'll now have a String s2 which, although it seems to be a one-character string, holds a reference to the gigantic char array created in the String s. This means the array won't be garbage collected, even though we've explicitly nulled out the String s!
The fix for this is to use our previously mentioned "useless" String constructor like this:
String s2 = new String(s.substring(0, 1));It's not well-known that this constructor actually copies that old contents to a new array if the old array is larger than the count of characters in the string. This means the old String contents will be garbage collected as intended. Happy happy joy joy.
Наконец, Кэт Марсен отмечает эти моменты,
First of all, string constants are never garbage collected. Second of all, string constants are intern'd, which means they are shared across the entire VM. This saves memory. But it is not always what you desire.
The copy constructor on String allows you to create a private String instance from a String literal. This can be very valuable for constructing meaningful mutex objects (for the purposes of synchronization).
Обратите внимание, что это больше не актуально со времен Java 7 (я думаю), где реализация String.substring() была изменена, чтобы избежать этой проблемы.
Мне жаль, что я отклоняю этот технически точный и хорошо проработанный ответ, но время сделало его менее актуальным (в основном интересно только с исторической точки зрения, но больше не применимо к текущим JVM).
Конструктор в значительной степени избыточен и не рекомендуется для общих целей. Конструктор String с аргументом String используется редко, за исключением создания независимой копии существующей строковой переменной. В основном используйте его, чтобы «прояснить» ваш код. Не меньше.
от 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){.....}
Чтобы расширить Ответ Дугласа *, я могу привести четкий пример того, где я его использовал. Рассмотрите возможность чтения файла словаря с тысячами строк, каждая из которых представляет собой одно слово. Самый простой способ прочитать это - использовать BufferedReader.readLine().
К сожалению, readLine() по умолчанию выделяет буфер из 80 символов в качестве ожидаемой длины строки. Это означает, что обычно можно избежать бессмысленного копирования - и немного потраченной впустую памяти обычно не так уж и плохо. Однако, если вы загружаете словарь коротких слов на время работы приложения, вы в конечном итоге потеряете много памяти. Мое «маленькое приложение» заняло гораздо больше памяти, чем должно было.
Решением было изменить это:
String word = reader.readLine();
в это:
String word = new String(reader.readLine());
... конечно, с комментарием!
* Я не могу вспомнить, работал ли я с Дугласом, когда это действительно произошло, или это просто совпадение, что он ответил именно на этот вопрос.
Разве «подстрока» или что-то еще, что вы использовали для ее вырезания, уже не создала новую строку?