Клонировать (метод Java) - Clone (Java method)

клон () это метод в Язык программирования Java за дублирование объекта. В Java объекты управляются с помощью ссылочных переменных, и нет оператора для копирование объект - оператор присваивания дублирует ссылку, а не объект. Эту недостающую функциональность обеспечивает метод clone ().

Обзор

Классы, которым нужна функция копирования, должны реализовать для этого какой-то метод. В определенной степени эту функцию обеспечивает "Object.clone ()".

клон () действует как конструктор копирования. Обычно он вызывает клон () метод своего суперкласса для получения копии и т. д., пока он в конечном итоге не достигнет Объектс клон () метод. Специальный клон () метод в базовый класс Объект предоставляет стандартный механизм для дублирования объектов.

В класс Объектс клон () создает и возвращает копию объекта с тем же классом и со всеми полями, имеющими одинаковые значения. Однако, Object.clone () бросает CloneNotSupportedException если объект не является экземпляром класса, реализующего маркер интерфейс Клонируемый.

Реализация по умолчанию Object.clone () выполняет мелкая копия. Когда класс желает глубокая копия или какое-либо другое настраиваемое поведение, они должны реализовать это в собственном клон () после получения копии из суперкласса.

Синтаксис для вызова клон в Java (при условии объект переменная типа класса, имеющая общедоступный клон () метод):

Объект копировать = объект.клон();

или обычно

Мой класс копировать = (Мой класс) объект.клон();

который обеспечивает приведение типов нужно было назначить генерала Объект ссылка возвращена из клон на ссылку на Мой класс объект.

Один недостаток конструкции клон () метод заключается в том, что возвращаемый тип клон () является Объект, и его необходимо явно привести обратно к соответствующему типу. Однако преобладающий клон () для возврата соответствующего типа предпочтительнее и устраняет необходимость приведения типов в клиенте (используя ковариантные возвращаемые типы, начиная с J2SE 5.0).

Еще один недостаток - часто не удается получить доступ к клон () метод абстрактного типа. Большинство интерфейсов и абстрактных классов в Java не определяют общедоступный клон () метод. В результате часто клон () Метод может использоваться только в том случае, если известен фактический класс объекта, что противоречит принципу абстракции использования наиболее универсального типа. Например, если у кого-то есть Список ссылка в Java, нельзя вызывать клон () по этой ссылке, потому что Список не определяет публичных клон () метод. Фактические реализации Список подобно ArrayList и LinkedList у всех вообще есть клон () методы сами по себе, но переносить фактический тип класса объекта неудобно и плохо.

Альтернативы

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

Также использование сериализации и десериализации является альтернативой использованию clone.

Шаблон Singleton

При написании класса с использованием Шаблон Singleton, единовременно может существовать только один экземпляр этого класса. В результате классу нельзя разрешить создавать клон. Чтобы предотвратить это, можно переопределить клон () метод, используя следующий код:

общественный Объект клон() бросает CloneNotSupportedException {    бросить новый CloneNotSupportedException();}

Это необходимо только в том случае, если суперкласс реализует общедоступный клон () метод, или запретить подклассу использовать этот класс клон () способ получения копии. Классы обычно не наследуют общедоступные клон () метод, потому что Объект не имеет публичного клон () метод, поэтому обычно нет необходимости явно реализовывать нефункциональный клон () метод.

Иерархия классов

Чтобы предоставить правильно клонируемый объект любого типа, метод clone () должен быть правильно объявлен и правильно реализован в соответствии с соглашением, описанным в Object.clone ().

1) Каждый тип, который необходимо клонировать, должен иметь общедоступный метод clone () в собственном классе или общедоступный метод clone () в одном из его родительских классов.

Пример:

Чтобы вызвать clone () для varY1, имеющего тип Y, Y или родительский элемент Y должны объявить общедоступный метод clone (). Здесь родительский класс X предоставляет общедоступный метод clone ().

общественный класс Икс орудия Клонируемый {        общественный Икс клон() бросает CloneNotSupportedException {                вернуть (Икс) супер.клон();        }}общественный класс Y расширяет Икс { }общественный класс Z расширяет Y { }общественный класс test1 {        общественный пустота функция() бросает CloneNotSupportedException {                Y varY1 = новый Z();                Y varY2 = (Y) varY1.клон();        }}

2) Каждый класс, реализующий clone (), должен вызывать super.clone () для получения ссылки на клонированный объект. Если в классе есть ссылки на объекты, которые также необходимо клонировать (например, при глубоком копировании), то метод clone () должен выполнить все необходимые изменения объекта перед его возвратом. (Поскольку Object.clone () возвращает точную копию исходного объекта, любые изменяемые поля, такие как коллекции и массивы, будут совместно использоваться оригиналом и копией, что в большинстве случаев не ожидается и не желательно.)

Пример:

Поскольку класс Z содержит ссылку на объект, его метод clone () также клонирует эту ссылку на объект, чтобы вернуть полную копию оригинала.

общественный класс Икс орудия Клонируемый {        общественный Икс клон() бросает CloneNotSupportedException {                вернуть (Икс) супер.клон();        }}общественный класс Y расширяет Икс { }общественный класс ObjectABC орудия Клонируемый {        общественный ObjectABC клон() бросает CloneNotSupportedException {                вернуть (ObjectABC) супер.клон();        }}общественный класс Z расширяет Y {        частный ObjectABC someABC;        общественный Z клон() бросает CloneNotSupportedException {                Z newZ = (Z) супер.клон();                newZ.someABC = someABC.клон();                вернуть newZ;        }}общественный класс test1 {        общественный пустота функция() бросает CloneNotSupportedException {                Y varY1 = новый Z();                Y varY2 = (Y) varY1.клон();        }}

Ловушки

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

В случае сложных графов объектов глубокое копирование также может стать проблематичным при наличии рекурсивных ссылок.

Не всегда уместно иметь несколько копий одного и того же объекта, плавающего вокруг. Если цель конкретной клон () реализация не совсем понятна потребителям, она может непреднамеренно нарушить парадигму «один объект - несколько ссылок».

Заключительные поля

В общем, клон () несовместимо с окончательный поля. Потому что клон () по сути является конструктором по умолчанию (тот, у которого нет аргументов), невозможно назначить окончательный поле в клон () метод; результатом является ошибка компилятора. Если значением поля является неизменный объект это нормально; просто позвольте «конструктору» скопировать ссылку, и оригинал и его клон будут использовать один и тот же объект.

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

По этой причине некоторые программисты предлагают делать объекты в иерархии Сериализуемый, и создавать копии, сериализуя старый объект, а затем создавая новый объект из полученного битовый поток, который правильно обрабатывает окончательные данные, но работает значительно медленнее.[1]

В качестве альтернативы можно вернуть полностью новый объект из полей текущих объектов, что можно сделать сначала вызовом конструктора, а затем назначением не конечных полей. Другой альтернативный метод фактически делает идею формальной: создание конструктора копирования, который принимает экземпляр. Фактически, это то, что некоторые люди рекомендуют вместо клона.[2]

Рекомендации

  1. ^ Миллер, Дэйв (6 августа 1999 г.). «Совет по Java 76: альтернатива технике глубокого копирования». JavaWorld. Получено 2020-07-14.
  2. ^ Clone () против конструктора копирования, который рекомендуется в java, Переполнение стека

внешняя ссылка