Java clone не работает

Русские Блоги

[Java] Проблема с правами доступа, вызванная методом Object.clone ()

[Java] Проблема с правами доступа, вызванная методом Object.clone ()

В процессе изучения Java я видел это предложение в «Технология ядра Java» (Том 1) «Поскольку метод clone () в классе Object защищен, его нельзя вызвать напрямую в форме anObject.clone (). Когда я это увидел, я был немного озадачен. Когда я учился раньше, мое понимание защищенного было таким

Защищенные измененные классы и атрибуты видны вам, этому пакету и его подклассам

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

Редактор напрямую подскажет

‘clone() has protected access in ‘java.lang.Object’’

Причина такой ситуации на самом деле в том, что предыдущее понимание защищенного несколько односторонне, а точное понимание защищенного

Для защищенных членов или методов, находятся ли молекулярный класс и суперкласс в одном пакете. Подклассы, не входящие в тот же пакет, что и базовый класс, могут получить доступ только к защищенным членам, унаследованным от базового класса, но не к защищенным членам самого экземпляра базового класса. В одном пакете protected и public — одно и то же

В этом примере, то есть, хотя и test, и test2 являются подклассами Object, поскольку метод clone () защищен, а test и Object не находятся в одном пакете, методы в test могут получить доступ только к себе из базы Защищенные члены (то есть метод clone ()) унаследованы от класса (Object в этом примере), но не могут получить доступ к защищенным членам самого экземпляра базового класса (то есть, пытаясь использовать a.clone () таким образом Вызвать метод clone ())

Фактически, когда мы вызываем метод clone () таким образом, обратите внимание, что a является экземпляром test вместо экземпляра test2, и компилятор предложит

Хотя программа по-прежнему не может работать нормально, это не предыдущая проблема с разрешениями, которая препятствует запуску программы. Это также показывает, что тест может вызывать свой собственный метод clone (), унаследованный от Object. Что касается источника этого исключения, давайте перейдем к Глядя на исходный код метода Object.clone (), вы можете найти следующий абзац

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

  • @return: представляет клон экземпляра, возвращаемого этим методом, что не слишком отличается от наших ожиданий.
  • @throws: Собственно, именно по этой причине наша программа сейчас не может нормально работать. Содержимое после @throws объясняетЕсли класс не реализует интерфейс Cloneable или подкласс пытается переопределить метод клонированияВыдает исключение CloneNotSupportedException это исключение

На практике, если вы хотите использовать метод clone (), вы обычно выполняете следующие операции:

1. Реализуйте интерфейс Cloneable, вот еще одно предложение, на самом деле Cloneable — этоИнтерфейс тегов, Так называемый интерфейс маркировки, как следует из названия, представляет собой интерфейс, используемый для маркировки классов, то есть этот интерфейс на самом деле не имеет какого-либо содержимого, мы можем проверить исходный код Cloneable, и вы также можете увидеть соответствующее объяснение

Читайте также:  Как отремонтировать поломанный кончик спиннинга

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

  • Все переменные объекта, скопированного мелким клоном, содержат то же значение, что и исходный объект, и все ссылки на другие объекты по-прежнему указывают на исходный объект. Другими словами, объект после клонирования все еще имеет некоторые ассоциации с объектом ранее, и степень клонирования невысока, поэтому это также называется поверхностным клонированием.
  • Все переменные, скопированные глубоким клоном, имеют то же значение, что и исходный объект, и те переменные, которые относятся к другим объектам, будут указывать на скопированные новые объекты вместо исходных объектов, на которые имеются ссылки. Другими словами, глубокая копия копирует все объекты, на которые ссылается копируемый объект.

Вот также простой пример реализации указанного выше метода:

Из приведенных выше результатов видно, что имя и возраст в клонированном объекте Player являются новыми и могут быть изменены с помощью методов setName и setAge, но тренер используется совместно с исходным. Изменение тренера клонированного объекта также повлияет на исходный объект. тренер, это мелкий клон.

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

Источник

Как правильно клонировать объект?

Для клонирования объекта в Java можно пользоваться тремя способами:

  1. Переопределение метода clone() и реализация интерфейса Cloneable();
  2. Использование конструктора копирования;
  3. Использовать для клонирования механизм сериализации

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

Из примера выше видно, что у клона и оригинала состояние одного из полей изменяется одновременно. Следующий способ заключается в использовании конструктора копирования:

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

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

Ни один кот не пострадал в результате тестов, мы видим что Васька был сохранён в поток, из которого затем восстановили независимый клон. Если нет особой необходимости обработки полей во время клонирования объектов, то сериализация является наиболее предпочтительным вариантом для этих целей.

Источник

Методы объектов Java: clone()

Автор: Adam McQuistan
Дата записи

Вступление

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

  • Струна
  • в класс
  • равняется
  • Хэш-код
  • клон (вы здесь)
  • завершать
  • ждать и уведомлять
Читайте также:  Word переводчик не работает

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

Почему существует необходимость клонировать() объект

Сначала я хотел бы начать с того, почему в первую очередь может потребоваться создать клон или копию объекта. Я снова буду использовать свой класс Person из предыдущих статей этой серии для демонстраций, особенно важно то, что это изменяемая его версия, иначе копирование было бы спорным вопросом.

Код показан ниже:

Я начинаю свое обсуждение с создания пары целочисленных переменных x и y вместе с экземпляром Person и назначаю его переменной с именем me . Затем я назначаю me другой переменной с именем me2 , которую затем изменяю в поле Имя в me2 и показываю содержимое обеих переменных, например:

Теперь есть хороший шанс, что многие из вас уловили это маленькое ” ой ” … но, чтобы все были на одном уровне понимания, позвольте мне объяснить, что там только что произошло. В Java у вас есть две основные категории типов данных: типы значений (они же примитивы) и ссылочные типы (они же объекты). В моем примере выше объекты Person, такие как me и me2 , относятся к ссылочному типу объекта Person. В отличие от типов ссылок на человека x и y являются типами значений примитивов int.

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

Вот почему, когда я изменил значение поля Имя ссылочной переменной me2 , я также увидел такое же изменение в ссылочной переменной me , они ссылались на один и тот же объект в памяти. По этим причинам становится важным иметь возможность создавать фактические копии (клоны) ссылочных объектов и, следовательно, необходимость в методе clone () .

Как клонировать() объект

Как я упоминал ранее, метод clone() класса объектов вызывает некоторые разногласия в сообществе разработчиков Java. Причины этого в том, что для реализации метода clone() вам необходимо реализовать причудливый интерфейс, называемый Cloneable из пакета “java.lang”, который предоставляет вашему классу возможность предоставлять общедоступный clone() метод. Это необходимо, поскольку метод clone() в классе объектов защищен и, следовательно, недоступен из клиентского кода, работающего с вашим классом. Кроме того, поведение при создании объекта довольно необычно в том смысле, что экземпляр создается без вызова желанного оператора new , что вызывает у многих, включая меня, некоторое беспокойство.

Однако для полноты я опишу действительный способ реализации правильно переопределенного метода clone() при реализации интерфейса Cloneable , но я также закончу некоторыми альтернативными механизмами для создания новых экземпляров объектов более идиоматичным способом Java-esk.

Хорошо, без дальнейших шуток я продолжу объяснять, как клонировать объекты с помощью clone() в моем классе Person. Сначала я реализую интерфейс Cloneable и добавлю публично переопределенный метод clone () , который возвращает экземпляр объекта типа.

Для простого класса, такого как Person, который не содержит никаких изменяемых полей, все, что требуется для создания клона, – это вернуть вызов метода клонирования объекта базового класса, например:

Читайте также:  Не работает концевик двери опель зафира

В этом примере создание клона человека довольно просто и выполняется примерно так:

Вуаля, я клон сделан. Теперь, когда я обновляю Имя свойство me2 , используя предыдущий пример, поле в объекте me остается неизменным. Обязательно обратите внимание на явное приведение возвращенного клона объекта типа к типу Person, которое необходимо, поскольку интерфейс требует возврата ссылки на объект типа.

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

Чтобы продемонстрировать это, мне нужно обновить свой Человек класс вот так.

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

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

Альтернативные методы создания копий экземпляров

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

Для начала я расскажу о методе конструктора копирования. Этот способ создания копий объектов с помощью конструктора основан на подписи, которая содержит только один параметр собственного типа, представляющий копируемый объект, такой как публичное лицо(Лицо p) .

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

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

Вот пример использования конструктора копирования для класса Person :

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

Сравнение различий в реализации

Создание копий объекта Java с помощью реализации Cloneable и переопределения clone() по праву получило плохую репутацию. Это связано с тем, что интерфейс witch изменяет видимость самого метода clone () , а также с часто недооцениваемой необходимостью “глубокого” клонирования изменяемых ссылочных типизированных полей класса. По этим причинам я предпочитаю использовать конструкторы копирования и фабричные методы для создания копий объектов. Только когда я работаю с классом, который специально реализовал интерфейс Cloneable , я продолжу использовать метод clone () .

Вывод

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

Как всегда, спасибо за чтение и не стесняйтесь комментировать или критиковать ниже.

Источник

Оцените статью