В некоторых случаях это имеет смысл. Строки Java являются хорошим примером. Когда строка создается в Java, она имеет ссылку на вспомогательный массив символов (a char[]
). Он знает смещение в массиве char и длину строки. Когда вы создаете подстроку, это относится к тому же массиву поддержки. Теперь рассмотрим этот код:
String x = buildVeryLongString();
String y = x.substring(0, 5);
// Use y a lot, but x is garbage collected
Тот факт, что y
все еще находится в системе, означает, что оригинал char[]
, используемый x
, все еще требуется. Другими словами, вы используете больше памяти, чем должны. Если вы измените код на:
String x = buildVeryLongString();
String y = new String(x.substring(0, 5));
тогда вы в конечном итоге скопируете данные в новый char[]
. Когда x
и y
имеют примерно одинаковое время жизни , этот подход приводит к потере памяти (имея две копии), но в случае, когда x
- сборщик мусора до y
, это может привести к большому разница.
Я сталкивался с подобным примером со строками в реальной жизни при чтении слов из словаря. По умолчанию BufferedReader.readLine()
будет использовать буфер из 80 символов для начала строки, поэтому любая (непустая) строка, возвращаемая readLine()
, будет ссылаться на массив char[]
длиной не менее 80 символов. Если вы читаете файл словаря с одним словом в строке, это много потерянного пространства!
Это только пример, но он показывает разницу между двумя неизменяемыми объектами, которые семантически эквивалентны с точки зрения того, что вы делаете с ними, но имеют другие характеристики в других отношениях. То, что обычно является причиной того, что вы хотите скопировать неизменяемый тип, но это все еще довольно редкая вещь, которую нужно делать.
В .NET строки хранятся несколько иначе - символьные данные хранятся внутри самого строкового объекта, а не в отдельном массиве. (Насколько мне известно, массивы, строки и IntPtr
являются единственными типами переменных размеров в .NET). Однако "буфер" в строке может быть больше, чем должен быть. Например:
StringBuilder builder = new StringBuilder(10000);
builder.Append("not a lot");
string x = builder.ToString();
Строковый объект, на который ссылается x
, будет иметь огромный буфер. Изменение последней строки на builder.ToString().Copy()
сделает большой буфер пригодным для сбора мусора немедленно, оставив вместо этого небольшую строку. Опять же, делать это безоговорочно - плохая идея, но в некоторых случаях это может быть полезно.