Чем отличается копирование от клонирования java
Перейти к содержимому

Чем отличается копирование от клонирования java

  • автор:

Разница между клонированием и копированием

Клонированием называют поверхностное копирование (то, что реализуется защищенным по умолчанию методом clone любого потомка Object). Однако копирование может быть и полным.
То есть клонирование — просто частный случай копирования.

Остальные ответы

Операция клонирования (Edit • Clone) отличается от дублирования (копирования) двумя особенностями. Во-первых, клон наследует свойства контура и заполнения исходного объекта и сохраняет связь с этими свойствами: изменение свойств исходного объекта вызывает соответствующие изменения у клона. Во-вторых, операция клонирования «одноступенчатая»: нельзя создать клон от клона.

Разбираемся с копированием и клонированием

Я наткнулся на статью Нареша Джоши о копировании и клонировании и был удивлён ситуацией с производительностью. У клонирования есть проблемы с финальными полями. А учитывая тот факт, что интерфейс Cloneable не предоставляет метод clone , то для вызова clone вам необходимо будет знать конкретный тип класса.

Вы можете написать такой код:

 ((Cloneable)o).clone(); // не работает

Если интерфейс Cloneable сломан, то у механизма клонирования могут быть некоторые преимущества. При копировании памяти он может оказаться эффективнее, чем копирование поля за полем. Это подчёркивает Джош Блох, автор Effective Java:

Даг Ли пошёл ещё дальше. Он сказал мне, что теперь клонирует только при копировании массивов. Вам следует использовать клонирование копирования массивов, потому что в целом это самый быстрый способ. Но у Дага типы больше не реализуют Cloneable . Он с ним завязал. И я не считаю это необоснованным.

Но это было в 2002-м, разве ситуация не изменилась? Со времён Java 6 у нас есть Arrays.copyOf , что насчёт него? Какова производительность копирования объекта?
Есть только один способ выяснить: прогнать бенчмарки.

TL;DR

  • Клонирование работает быстрее при копировании массива, это заметно на маленьких массивах.
  • Arrays.copyOf и clone примерно одинаково работают
  • Клонирование работает медленнее для маленьких объектов, меньше восьми полей, но в любом случае быстрее.
  • При клонировании не работает escape analysis, и потенциально оно может помешать применению других оптимизаций.

image

Массивы

[UPD]Andrei Paguin указал в комментариях что с бенчмарком есть проблема.

замените “size” на “original.length” в бенчмарке Arrays.copyOf().

И тут я понял, что да… это объясняет почему jit может понять что мы копируем ровно такую же длину. Поэтому я изменил выводы и статью

Давайте быстро рассмотрим clone и Arrays.copyOf применительно к массивам.

Бенчмарк int array выглядит так:

 @Benchmark @CompilerControl(CompilerControl.Mode.DONT_INLINE) public int[] testCopy() < return Arrays.copyOf(original, original.length); // здесь было size >@Benchmark @CompilerControl(CompilerControl.Mode.DONT_INLINE) public int[] testClone()

Мы создали массив из случайных числовых значений, затем выполнили clone или Arrays.copyOf . Обратите внимание: мы вернули результат копирования, чтобы гарантировать, что код будет выполнен. В главе про escape analysis мы увидим, как невозвращение массива может радикально повлиять на бенчмарк.

Наряду с int array есть версия для byte array , long array и Object array . Я использую флаг DONT_INLINE , чтобы при необходимости легче было анализировать сгенерированный asm.

mvn clean install java -jar target/benchmark.jar -bm avgt -tu ns -rf csv
    здесь будут обновленные результаты —

В чем разница между копированием и клонированием?

Есть ли окончательная ссылка на это в программировании? Я вижу, что многие люди относятся к глубокому копированию и клонированию как к одному и тому же. Это правда? Является ли он зависимым от языка? Небольшая точка, но это меня беспокоило.

LWoodyiii 04 фев. 2010, в 16:06
Поделиться
Я не верю, что существует какой-либо четкий консенсус относительно их относительного значения.
Mitch Wheat 04 фев. 2010, в 14:38
Поделиться:

5 ответов

Лучший ответ

Нет формального определения этих понятий, по крайней мере, не одного, охватывающего все языки.

Что обычно обычно:

  • clone — создать что-то новое на основе чего-то, что существует.
  • копирование — копирование из чего-то, что существует в нечто другое (это уже существует).

Anonym 04 фев. 2010, в 15:05
Поделиться

Да, есть разница. Что касается языковых зависимостей, некоторые языки могут делать все мелкие, глубокие, ленивые копии. Некоторые только делают мелкие копии. Так что да, иногда это зависит от языка.

Теперь возьмите, например, массив:

int [] numbers = < 2, 3, 4, 5>; int [] numbersCopy = numbers; 

Теперь массив «numbersCopy» содержит те же значения, но, что более важно, сам объект массива указывает на ту же ссылку на объект, что и массив «numbers».

Итак, если бы я сделал что-то вроде:

 numbersCopy[2] = 0; 

Каким будет вывод для следующих операторов?

 System.out.println(numbers[2]); System.out.println(numbersCopy[2]); 

Учитывая, что оба массива указывают на ту же ссылку, мы получим:

Но что, если мы хотим сделать отдельную копию первого массива со своей ссылкой? В этом случае мы хотели бы клонировать массив. При этом каждый массив будет иметь свою собственную ссылку на объект. Посмотрим, как это будет работать.

 int [] numbers = < 2, 3, 4, 5>; int [] numbersClone = (int[])numbers.clone(); 

Теперь массив «numbersClone» содержит те же значения, но в этом случае сам объект массива указывает другую ссылку, чем массив «numbers».

Итак, если бы я сделал что-то вроде:

 numbersClone[2] = 0; 

Каким будет вывод для следующих операторов?

 System.out.println(numbers[2]); System.out.println(numbersClone[2]); 

Какой вариант лучше: клонирование или копирование конструкторов?

Вот как я начал писать эту статью. Я читал это утверждение много раз: «Клонирование становится трудным, когда у объекта есть ссылки на изменяемые конечные поля». И каждый раз, когда я гуглю об этом, понимаю, что именно это означает, и как часть процесса забываю об этом тоже. Поэтому я подумал, что я буду вести блог, чтобы это послужило моей непосредственной ссылкой.

Клонирование объекта, которое я мог вспомнить из моего курса ООП в аспирантуре, – это создание аналогичной копии объекта, которая в основном должна соответствовать следующим правилам:

  1. x.clone ()! = x
  2. x.clone (). getClass () == x.getClass ()
  3. x.clone (). равно (х)

Обратите внимание, что условие (1) всегда должно выполняться во всех случаях. Хотя условия (2) и (3) не являются абсолютными требованиями, хорошо спроектировать метод клонирования таким образом, чтобы он оставался в силе. Прежде чем продолжить обсуждение, вот сигнатура метода клона в классе Object:

protected native Object clone() throws CloneNotSupportedException;

Итак, как вы заметили, защищенный модификатор, мы не можем вызвать метод clone () непосредственно для любого объекта. Мы должны переопределить этот метод как открытый метод и обеспечить реализацию для него в нашем классе, чтобы получить к нему доступ. Если никакой конкретной реализации не требуется, мы можем просто вернуть super.clone (). Поскольку ковариантные возвраты возможны после Java 5, мы можем изменить возвращаемое значение clone, чтобы вернуть объект нашего класса. Итак, если мы пишем наш класс работника, вот как метод clone () хотел бы:

public Employee clone() throws CloneNotSupportedException < return (Employee) super .clone();

Но обратите внимание, что метод clone в классе Object проверяет, реализует ли наш класс интерфейс Cloneable. Если он не реализует его, он создает исключение CloneNotSupportedException. В противном случае он создает новую копию. Но обратите внимание, что метод clone никогда не вызывает конструктор для создания копии объекта. Поэтому, если вы хотите отслеживать количество экземпляров, создаваемых для класса, увеличивая статический счетчик внутри конструктора, это не сработает, так как конструктор никогда не вызывается. Вместо этого метод clone выполняет полевое копирование свойств экземпляра из памяти объекта и возвращает его вызывающей стороне. Поэтому класс должен реализовать интерфейс маркера Cloneable, если он должен предоставить возможность клонировать его без получения исключения CloneNotSupportedException. Но обратите внимание, что код, который вызывает clone (), должен обрабатывать это исключение. В противном случае это приведет к ошибке компилятора. Да, это болевая точка, и за это критикуют.

Давайте рассмотрим пример: Case (1) :

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *