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
Сделать метод копирования объекта
Нужно сделать метод копирования (не через сlone, а в ручную) объекта. obj1=obj2; не подходит, так как оно просто ссылочку перекинет и все (класс — ссылочный тип). Нужно, чтобы 2 объект был независимым от второго, т.е. копирнул его — и есть возможность менять его, не трогая первый объект.
Отслеживать
30.9k 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. Копирование объекта — это создание копии существующего объекта для изменения или перемещения скопированного объекта без воздействия на исходный объект.
В отличие от C++, объекты Java передаются не по значению, а по значению передаются их ссылки. Рассмотрим следующие фрагменты кода,
Object ob1 = new Object();
Object ob2 = ob1;
Оба ob1 а также ob2 теперь указывает на тот же объект, так как это просто ссылка на исходные данные; здесь не происходит копирования.
Object ob = new Object();
fun(ob);
Это также просто ссылка на исходные данные, поскольку методы в Java всегда передаются по значению. Однако передается значение ссылочной переменной.
int a = 5;
int b = a;
Так как данные здесь примитивные, то просто копируется значение примитивного типа.
Иногда необходимо создать копию объекта для использования в приложении. В этом посте мы обсудим несколько способов достижения этого. Прежде чем мы начнем, давайте поговорим о мелком и глубоком копировании объектов.
1.Поверхностное копирование (копирование поля за полем)
Одним из способов копирования объекта является мелкая копия в котором мы выделяем новый неинициализированный объект и копируем в него все поля (атрибуты) из исходного объекта. Это не всегда приводит к желаемому поведению, когда значение поля является ссылкой на объект, поскольку оно копирует ссылку и, следовательно, ссылается на тот же объект, что и исходный объект. Таким образом, ссылочные объекты являются общими, поэтому, если один объект изменен, изменение видно в другом.

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

Существует несколько подходов к копированию объекта, как описано ниже:
1. Использование конструктора копирования или фабрики
С помощью Копировать конструктор, мы можем определить действия, выполняемые компилятором при копировании объекта класса. Любая реализация конструктора копирования должна выполнять глубокое копирование для любых объектов, на которые есть ссылки в классе, путем создания новых объектов и копирования значений для примитивных и неизменяемых типов. Обычно он принимает только один параметр, который является еще одним экземпляром того же класса.
Мы также можем использовать метод статической фабрики копий, чтобы по существу делать то же самое, что и метод конструктора копирования. Оба подхода показаны ниже:
Как реализовано глубокое клонирование в java
В Java глубокое клонирование можно реализовать двумя способами:
1 Реализовать интерфейс Cloneable и переопределить метод clone() .
При этом, необходимо скопировать все поля объекта и рекурсивно клонировать все объекты, которые содержатся в этом объекте.
public class MyClass implements Cloneable private int x; private String str; private MyOtherClass obj; // constructors, getters, and setters @Override public Object clone() throws CloneNotSupportedException MyClass cloned = (MyClass) super.clone(); cloned.obj = (MyOtherClass) obj.clone(); return cloned; > > public class MyOtherClass implements Cloneable private int y; private String str2; // constructors, getters, and setters @Override public Object clone() throws CloneNotSupportedException return super.clone(); > >
2 Использовать механизм сериализации объектов.
Для этого объект необходимо сериализовать в байтовый поток, а затем десериализовать обратно в объект. При десериализации создается новый объект с теми же полями и значениями, что и у исходного объекта.
public class MyClass implements Serializable private int x; private String str; private MyOtherClass obj; // constructors, getters, and setters public MyClass deepCopy() throws IOException, ClassNotFoundException ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (MyClass) ois.readObject(); > > public class MyOtherClass implements Serializable private int y; private String str2; // constructors, getters, and setters >
Оба способа имеют свои преимущества и недостатки, но использование механизма сериализации может быть медленнее и менее эффективным, чем использование метода clone()