Имеет смысл копировать неизменный тип?

Недавно я столкнулся с исключением java.lang.ClassNotFoundException: org.h2.Driver в IntelliJ IDEA 2017.2 EAP при использовании последней версии (1.4.196) драйвера H2 . Решение было снизить до 1.4.195, который работал.


    com.h2database
    h2
    1.4.195
    test

5
задан Joan Venge 6 June 2009 в 19:50
поделиться

6 ответов

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

12
ответ дан 18 December 2019 в 06:51
поделиться

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

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

4
ответ дан 18 December 2019 в 06:51
поделиться

К сожалению, я не верю, что на самом деле является лучшим способом сделать это из-за природы обработки Java примитивных типов, упаковки, массивов и обобщений. В частности:

  • List .toArray не будет работать, потому что нет преобразования из Integer в int
  • Вы не можете использовать int ] в качестве аргумента типа для дженериков, поэтому должен быть int -специфичным методом (или тем, который использовал отражение для совершения неприятных трюков).

Я считаю, что есть библиотеки, которые имеют автоматически сгенерированные версии этого типа метода для всех примитивных типов (т.е. есть шаблон, который копируется для каждого типа). Это некрасиво, но, боюсь, так оно и есть: m растягивая вещи сейчас ...

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

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

3
ответ дан 18 December 2019 в 06:51
поделиться

Класс 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 () , который делает то же самое.

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

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

2
ответ дан 18 December 2019 в 06:51
поделиться

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

Нет.

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

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

2
ответ дан 18 December 2019 в 06:51
поделиться

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

0
ответ дан 18 December 2019 в 06:51
поделиться
Другие вопросы по тегам:

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