Сделать метод копирования объекта
Нужно сделать метод копирования (не через сlone, а в ручную) объекта. obj1=obj2; не подходит, так как оно просто ссылочку перекинет и все (класс — ссылочный тип). Нужно, чтобы 2 объект был независимым от второго, т.е. копирнул его — и есть возможность менять его, не трогая первый объект.
Отслеживать
31k 13 13 золотых знаков 96 96 серебряных знаков 157 157 бронзовых знаков
задан 3 мар 2014 в 20:32
111xbot111 111xbot111
203 4 4 серебряных знака 21 21 бронзовый знак
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Как то так можно:
public class MyObject < private int field1; private String field2; private Listfield3 = new ArrayList(); // конструктор копий public MyClass(MyClass other) < // копировать все поля класса тут // примитивные типы передаются by value this.field1 = other.field1; // для остальных используем их конструкторы копий this.field2 = new String(other.field2); this.field3 = new ArrayList(other.field3); > // метод копирующий объект public MyClass copy() < return new MyClass(this); >>
Тут 2 способа, вызвать можно вот так:
MyObject obj1 = new MyObject(); //. MyObject obj2 = new MyObject(obj1); // или так MyObject obj2 = obj1.copy();
Вот почитайте, лучшие практики этого дела тут.
Клонирование
Иногда необходимо на основе существующего объекта создать второй такой же — то есть создать его клон. Это процесс в Java называется клонированием.
Для клонирования объекта в Java можно воспользоваться тремя способами:
- Переопределение метода clone() и реализация интерфейса Cloneable().
- Использование конструктора копирования.
- Использовать для клонирования механизм сериализации.
2. Переопределение метода clone()
Класс Object определяет метод clone(), который создает копию объекта. Если вы хотите, чтобы экземпляр вашего класса можно было клонировать, необходимо переопределить этот метод и реализовать интерфейс Cloneable. Интерфейс Clonable — это интерфейс маркер, он не содержит ни методов, ни переменных. Интерфейсы маркер просто определяют поведение классов.
Object.clone() выбрасывает исключение CloneNotSupportedException при попытке клонировать объект не реализующий интерфейс Cloneable.
Метод clone() в родительском классе Object является protected, поэтому желательно переопределить его как public. Реализация по умолчанию метода Object.clone() выполняет неполное/поверхностное (shallow) копирование. Рассмотрим пример:
Пример 1. Поверхностное клонирование
public class Car implements Cloneable < private String name; private Driver driver; public Car(String name, Driver driver) < this.name = name; this.driver = driver; >public String getName() < return name; >public void setName(String name) < this.name = name; >public Driver getDriver() < return driver; >public void setDriver(Driver driver) < this.driver = driver; >@Override public Car clone() throws CloneNotSupportedException < return (Car) super.clone(); >>
public class Driver implements Cloneable < private String name; private int age; public Driver(String name, int age) < this.name = name; this.age = age; >public String getName() < return name; >public void setName(String name) < this.name = name; >public int getAge() < return age; >public void setAge(int age) < this.age = age; >@Override public Driver clone() throws CloneNotSupportedException < return (Driver) super.clone(); >>
public class CloneCarDemo < public static void main(String[] args) throws CloneNotSupportedException < Car car = new Car("Грузовик", new Driver("Василий", 45)); Car clonedCar = car.clone(); System.out.println("Оригинал:\t" + car); System.out.println("Клон: \t" + clonedCar); Driver clonedCarDriver = clonedCar.getDriver(); clonedCarDriver.setName("Вася"); System.out.println("Оригинал после изменения имени водителя:\t" + car); System.out.println("Клон после изменения имени водителя: \t\t" + clonedCar); >>
В этом примере клонируются объект класса Car. Клонирование выполняется поверхностное — новый объект clonedCar содержит ссылку на тот же объект класса Driver, что и объект car. Если вас это не устраивает, то необходимо самим написать «глубокое» клонирование — создать новый объект класса Driver. Перепишем метод clone() класса Car:
Пример 2. Глубокое клонирование
@Override public Car clone() throws CloneNotSupportedException
3. Конструктор копирования
Еще один вариант клонирования объекта — это конструктор копирования. Создается конструктор, принимающий на вход объект того же класса, который необходимо клонировать:
Пример 3. Конструктор копирования с поверхностным клонированием
public class Car implements Cloneable < private String name; private Driver driver; public Car(String name, Driver driver) < this.name = name; this.driver = driver; >/** * Конструктор копирования. * * @param otherCar */ public Car(Car otherCar) < this(otherCar.getName(), otherCar.getDriver()); >public String getName() < return name; >public void setName(String name) < this.name = name; >public Driver getDriver() < return driver; >public void setDriver(Driver driver) < this.driver = driver; >>
Опять же — пример показывает неглубокое клонирование. Перепишем конструктор для реализации «глубокого» копирования:
Пример 4. Конструктор копирования с «глубоким» клонированием
public Car(Car otherCar) throws CloneNotSupportedException
Java как скопировать объект
При работе с объектами классов надо учитывать, что они все представляют ссылочные типы, то есть указывают на какой-то объект, расположенный в памяти. Чтобы понять возможные трудности, с которыми мы можем столкнуться, рассмотрим пример:
public class Program < public static void main(String[] args) < Person tom = new Person("Tom", 23); tom.display(); // Person Tom Person bob = tom; bob.setName("Bob"); tom.display(); // Person Bob >> class Person < private String name; private int age; Person(String name, int age)< this.name=name; this.age=age; >void setName(String name) < this.name = name; >void setAge(int age) < this.age = age; >void display() < System.out.printf("Person Name: %s \n", name); >>
Здесь создаем два объекта Person и один присваиваем другому. Но, несмотря на то, что мы изменяем только объект bob, вместе с ним изменяется и объект tom. Потому что после присвоения они указывают на одну и ту же область в памяти, где собственно данные об объекте Person и его полях и хранятся.

Чтобы избежать этой проблемы, необходимо создать отдельный объект для переменной bob, например, с помощью метода clone :
class Person implements Cloneable < private String name; private int age; Person(String name, int age)< this.name=name; this.age=age; >void setName(String name) < this.name = name; >void setAge(int age) < this.age = age; >void display() < System.out.printf("Person %s \n", name); >public Person clone() throws CloneNotSupportedException < return (Person) super.clone(); >>
Для реализации клонирования класс Person должен применить интерфейс Cloneable , который определяет метод clone . Реализация этого метода просто возвращает вызов метода clone для родительского класса — то есть класса Object с преобразованием к типу Person.
Кроме того, на случай если класс не поддерживает клонирование, метод должен выбрасывать исключение CloneNotSupportedException , что определяется с помощью оператора throws .
Затем с помощью вызова этого метода мы можем осуществить копирование:
try < Person tom = new Person("Tom", 23); Person bob = tom.clone(); bob.setName("Bob"); tom.display(); // Person Tom >catch(CloneNotSupportedException ex)
Однако данный способ осуществляет неполное копирование и подойдет, если клонируемый объект не содержит сложных объектов. Например, пусть класс Book имеет следующее определение:
class Book implements Cloneable < private String name; private Author author; public void setName(String n)< name=n;>public String getName() < return name;>public void setAuthor(String n) < author.setName(n);>public String getAuthor() < return author.getName();>Book(String name, String author) < this.name = name; this.author = new Author(author); >public String toString() < return "Книга '" + name + "' (автор " + author + ")"; >public Book clone() throws CloneNotSupportedException < return (Book) super.clone(); >> class Author < private String name; public void setName(String n)< name=n;>public String getName() < return name;>public Author(String name) < this.name=name; >>
Если мы попробуем изменить автора книги, нас постигнет неудача:
try < Book book = new Book("War and Peace", "Leo Tolstoy"); Book book2 = book.clone(); book2.setAuthor("Ivan Turgenev"); System.out.println(book.getAuthor()); >catch(CloneNotSupportedException ex)
В этом случае, хотя переменные book и book2 будут указывать на разные объекты в памяти, но эти объекты при этом будут указывать на один объект Author.

И в этом случае нам необходимо выполнить полное копирование. Для этого надо определить метод клонирования у класса Author:
class Author implements Cloneable < // остальной код класса public Author clone() throws CloneNotSupportedException< return (Author) super.clone(); >>
И затем исправим метод clone в классе Book следующим образом:
public Book clone() throws CloneNotSupportedException
Копирование объектов в Java
Часто встречается ситуация, когда при программировании на языке Java возникает необходимость создать копию объекта. Примером может служить следующий код:
Person person1 = new Person(); person1.setName("Иван"); Person person2 = person1; person2.setName("Петр"); System.out.println(person1.getName()); // выводит 'Петр'
В этом примере создается объект person1 класса Person , которому присваивается имя «Иван». Затем создается объект person2 , который является копией person1 . Изменение имени person2 на «Петр» приводит к тому, что имя person1 также меняется на «Петр».
Это происходит потому, что в Java при присваивании person2 = person1 копируется не сам объект, а ссылка на него. Это означает, что person1 и person2 указывают на один и тот же объект в памяти. В результате изменения, произведенные через одну переменную, отражаются на объекте, на который указывает другая переменная.
Для создания полноценной копии объекта в Java можно использовать метод clone() . Однако этот метод имеет свои нюансы и может быть не поддержан для некоторых классов. Кроме того, метод clone() создает поверхностную копию объекта, что может быть недостаточно, если объект содержит ссылки на другие объекты.
Более предпочтительным способом копирования объектов в Java является использование конструктора копирования или метода фабрики. Конструктор копирования — это конструктор, который принимает объект того же класса в качестве параметра. Метод фабрики — это статический метод, который принимает объект и возвращает его копию.
Пример использования конструктора копирования:
public class Person < private String name; public Person() < >public Person(Person original) < this.name = original.name; >// остальной код класса >
Пример использования метода фабрики:
public class Person < private String name; public static Person copyOf(Person original) < Person copy = new Person(); copy.name = original.name; return copy; >// остальной код класса >
В обоих случаях создается новый объект, который является копией исходного. Изменения в исходном объекте не отражаются на копии.