Думай на Java

       

Добавление клонируемости в класс


Несмотря на то что метод клонирования определен в классе Object, являющемся базовым для всех классов Java, это не означает что он автоматически может быть применен к любому классу [81]. Казалось бы, это идет в разрез с принципом наследования дочерними объектами методов родительских классов. Действительно, в Java клонирование идет вразрез с этим принципом. Поэтому, если вы хотите сделать эту функцию доступной для вашего класса, вы должны написать соответствующий код, обеспечивающий правильную работу метода клонирования.

Использование приема с protected

Для блокирования возможности клонирования во всех классах Java, в базовом классе Object метод clone() был описан как защищенный (protected). Это не только исключает возможность использования метода клонирования программистом, просто использующим (не расширяющим) этот класс, но и означает что вы не можете использовать clone() используя ссылку на базовый класс. (Хотя это может показаться полезным. Например, при полиморфном клонировании связок классов Object). Такой метод применен для того, чтобы на этапе компиляции информировать о том что данный объект является неклонируемым. Как ни странно, большинство классов стандартных библиотек Java неклонируемые. Поэтому, написав:

Integer x = new Integer(1);

x = x.clone();

на этапе компиляции это приведет к возникновению ошибки. Компилятор выдаст сообщение о том что метод clone() недоступен (поскольку Integer не переопределяет его и он по умолчанию является защищенным (protected)). Однако, если вы работаете с классом, производным от  Object (а это все классы языка Java), то у вас есть возможность вызвать метод Object.clone(), поскольку этот метод является защищенным (protected), а ваш объект является объектом-наследником по отношению к классу Object. Метод clone() класса Object обладает полезными функциональными возможностями - он осуществляет поразрядное дублирование передаваемого класса объекта, что и является основной операцией при клонировании объекта. Тем не менее вам будет необходимо написать собственный метод клонирования и описать ее как public. Итак, два ключевых момента при реализации клонировании это:


  • обязательный вызов метода super.clone()


  • написание собственного public метода клонирования 


  • В дальнейшем вам возможно понтребуется переопределить ваш метод clone() для классов-наследников, поскольку иначе при их клонировании будет использоваться ваш (теперь уже public) метод clone(), который может не выполнять своих функций для этих классов (хотя, поскольку создание копии самого объекта осуществляет метод Object.clone(), подобных проблем может и не быть). Такой прием с переопределением защищенного (protected) метода clone() может применяться только когда вы наследуете не клонируемый класс и хотите на его базе создать класс, поддерживающий клонирование. При этом для все классы, наследующие ваш класс, в свою очередь унаследуют и созданный вами метод clone(), поскольку в Java нельзя изменять статус наследуемых методов. Иными словами, если ваш класс является клонируемым, то и все наследующие его классы также будут клонируемыми, если только вы не примените приемы "отключения" клонируемости (они подробно рассмотрены далее).

    Реализация интерфейса Cloneable


    Для создания клонируемых объектов вам понадобятся навыки реализации Cloneable интерфейса. Этот интерфейс примечателен уже тем, что он совершенно пустой!

    interface Cloneable {}

    Очевидно, что причины наследования пустого интерфейса никак не связаны с последующим использованием его методов. В данном случае интерфейс используется в нестандартных целях. Он служит своего рода "меткой" для типа класса. Существуют две причины существования интерфейса Cloneable. Первая заключается в том, что вы можете использовать ссылки на базовый тип и при этом не знать, является ли он клонируемым или нет. В таких случаях вы можете использовать ключевое слово instanceof (рассмотренное в главе 12) для выяснения, является ли объект с которым связана ссылка клнируемым:

    if(myReference instanceof Cloneable) // ...

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


    Содержание раздела