Имеет ли смысл копировать неизменяемый тип? - PullRequest
5 голосов
/ 06 июня 2009

Имеет ли смысл реализовывать метод копирования для неизменяемого типа, возвращая новый экземпляр? Или это просто текущий экземпляр?

Я думал, что тип все равно не меняется, так зачем копировать? Как никто не копирует число 5, верно?

Ответы [ 6 ]

12 голосов
/ 07 июня 2009

В некоторых случаях это имеет смысл. Строки 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() сделает большой буфер пригодным для сбора мусора немедленно, оставив вместо этого небольшую строку. Опять же, делать это безоговорочно - плохая идея, но в некоторых случаях это может быть полезно.

4 голосов
/ 07 июня 2009

Технически, целое число является типом значения, поэтому оно постоянно копируется. :)

Тем не менее создание копии неизменяемого объекта не имеет смысла. Примеры строк, предоставленных другими, похоже, помогают при утечке абстракции этими классами.

3 голосов
/ 07 июня 2009

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

Существует несколько сомнительных причин для клонирования неизменяемого объекта:

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

Если мы расширим обсуждение, чтобы рассмотреть клонирование deep , тогда оно станет более разумным, поскольку обычный неизменяемый объект не подразумевает, что любые связанные объекты также являются неизменяемыми. Глубокий клон это исправит, но это отдельное соображение.

Я думаю, что, возможно, сценарий remoting - лучшее, что я могу сделать ...

2 голосов
/ 07 июня 2009

Имеет ли смысл предоставить «копию» операция над неизменным объектом?

номер

(В других ответах есть много других интересных дискуссий, но я подумал, что дам краткий ответ.)

Если указанному объекту необходимо реализовать интерфейс, для которого требуется метод Clone () (или моральный эквивалент), то можно «вернуть это».

2 голосов
/ 07 июня 2009

Ну, у класса String Java есть это:

String(String original)
      Initializes a newly created 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.

и .Net имеет метод Copy(), который делает то же самое.

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

Я просто не уверен, когда это будет ...

0 голосов
/ 06 июня 2009

Одним из преимуществ неизменяемых типов является то, что они могут быть интернированы (например, строки Java). Конечно, вам не следует делать дополнительные копии, если вы можете избежать этого.

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