Метод clone()
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 43 из 87.
Метод clone() создает копию объекта. Чтобы использовать его, ваш класс должен реализовать интерфейс Cloneable и переопределить метод clone() из класса Object.
public class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}Теперь вы можете создавать независимые копии объектов:
Person original = new Person("Alice", 25);
Person copy = original.clone();
// copy — это отдельный объект с теми же значениямиПо умолчанию clone() выполняет поверхностное копирование, что означает копирование примитивных значений и ссылок. Если ваш объект содержит другие объекты в качестве полей, и оригинал, и клон будут ссылаться на одни и те же вложенные объекты. Для создания по-настоящему независимых копий с вложенными объектами вам необходимо реализовать глубокое копирование, также клонируя эти вложенные объекты внутри вашего метода clone().
Задание
ЛегкоДавайте создадим систему управления документами, которая демонстрирует клонирование объектов. Вы создадите класс Document, который можно клонировать для создания независимых копий, что позволит пользователям дублировать документы, сохраняя оригинал нетронутым.
Вы организуете свой код в двух файлах:
Document.java: Создайте класс, представляющий документ, который поддерживает клонирование. Document имеет три приватных поля:title(String),author(String) иversion(int). Включите конструктор для инициализации всех полей и методы-геттеры для каждого из них. Также добавьте методsetVersion(int version)для обновления номера версии.Сделайте так, чтобы ваш класс Document реализовывал интерфейс
Cloneableи переопределял методclone()для возвратаDocument. Обработайте исключениеCloneNotSupportedExceptionвнутри метода, обернув его вRuntimeException.Переопределите
toString(), чтобы он возвращал:Document[title=X, author=Y, version=Z], где X, Y и Z — это фактические значения полей.Main.java: Оживите ваш класс Document, создав документ и клонировав его. Вы получите три входных значения: заголовок (String), автора (String) и номер версии (int).Создайте оригинальный Document с этими значениями, затем клонируйте его, чтобы создать копию. После клонирования измените версию копии, увеличив ее на 1 с помощью
setVersion(). Это продемонстрирует, что клон действительно независим от оригинала.Выведите три строки:
Original:за которым следует toString() оригинального документаClone:за которым следует toString() клонированного документаIndependent:за которым следуетtrueилиfalse, указывающее, являются ли оригинал и клон разными объектами (используйте сравнение!=)
Вы получите три входных значения: заголовок документа (String), имя автора (String) и номер версии (int).
Обратите внимание, как после изменения версии клона оригинальный документ остается неизменным — это доказывает, что clone() создал по-настоящему независимую копию!
Шпаргалка
Метод clone() создает копию объекта. Чтобы использовать его, ваш класс должен реализовать интерфейс Cloneable и переопределить метод clone() из класса Object:
public class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}Создание независимых копий:
Person original = new Person("Alice", 25);
Person copy = original.clone();
// copy — это отдельный объект с теми же значениямиПо умолчанию clone() выполняет поверхностное копирование, копируя примитивные значения и ссылки. Если ваш объект содержит другие объекты в качестве полей, и оригинал, и копия будут ссылаться на одни и те же вложенные объекты. Для создания по-настоящему независимых копий с вложенными объектами реализуйте глубокое копирование, также клонируя эти вложенные объекты внутри вашего метода clone().
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Чтение входных данных
String title = scanner.nextLine();
String author = scanner.nextLine();
int version = scanner.nextInt();
// TODO: Создать оригинальный Document с входными значениями
// TODO: Клонировать оригинальный документ, чтобы создать копию
// TODO: Изменить версию клона, увеличив её на 1
// TODO: Вывести "Original: " и следом оригинальный документ
// TODO: Вывести "Clone: " и следом клонированный документ
// TODO: Вывести "Independent: " и следом true/false (проверить, что original != clone)
}
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»