- How do we copy objects in java?
- Using copy constructor
- Example
- Output
- Using the clone method
- Example
- Output
- Метод Clone() в Java
- 1. Использование Object.clone() метод
- Java: Copying Objects
- Copy Constructors
- Copy Constructors and Inheritance
- Pros
- Cons
- Copy Factory Methods
- Pros
- Cons
- Serialization / Deserialization
- Pros
- Cons
- Object.clone
- Pros
- Cons
- Simple copy method
- Pros
- Cons
- Builders
- Pros
- Cons
How do we copy objects in java?
In Java you can copy an object in several ways, among them, copy constructor and the clone method are the mostly used.
Using copy constructor
Generally, the copy constructor is a constructor which creates an object by initializing it with an object of the same class, which has been created previously. Java does support for copy constructors but you need to define them yourself.
Example
In the following Java example, we a have a class with two instance variables name and age and a parameterized constructor initializing these variables.
Then, we have another constructor which accepts an object of the current class and initializes the instance variables with the variables of this object.
If you instantiate this class using the second constructor by passing an object to it, this results an object which is the copy of the one which you passed as an argument.
import java.util.Scanner; public class Student < private String name; private int age; public Student(String name, int age)< this.name = name; this.age = age; >public Student(Student std) < this.name = std.name; this.age = std.age; >public void displayData() < System.out.println("Name : "+this.name); System.out.println("Age : "+this.age); >public static void main(String[] args) < Scanner sc =new Scanner(System.in); System.out.println("Enter your name "); String name = sc.next(); System.out.println("Enter your age "); int age = sc.nextInt(); Student std = new Student(name, age); System.out.println("Contents of the original object"); std.displayData(); System.out.println("Contents of the copied object"); Student copyOfStd = new Student(std); copyOfStd.displayData(); >>
Output
Enter your name Krishna Enter your age 20 Contents of the original object Name : Krishna Age : 20 Contents of the copied object Name : Krishna Age : 20
Using the clone method
The clone() method of the class java.lang.Object accepts an object as a parameter, creates and returns a copy of it.
Example
In the following Java example, we a have a class with two instance variables name and age and a parameterized constructor initializing these variables.
From the main method we are creating an object of this class and generating a copy of it using the clone() method.
import java.util.Scanner; public class CloneExample implements Cloneable < private String name; private int age; public CloneExample(String name, int age)< this.name = name; this.age = age; >public void displayData() < System.out.println("Name : "+this.name); System.out.println("Age : "+this.age); >public static void main(String[] args) throws CloneNotSupportedException < Scanner sc =new Scanner(System.in); System.out.println("Enter your name "); String name = sc.next(); System.out.println("Enter your age "); int age = sc.nextInt(); CloneExample std = new CloneExample(name, age); System.out.println("Contents of the original object"); std.displayData(); System.out.println("Contents of the copied object"); CloneExample copiedStd = (CloneExample) std.clone(); copiedStd.displayData(); >>
Output
Enter your name Krishna Enter your age 20 Contents of the original object Name : Krishna Age : 20 Contents of the copied object Name : Krishna Age : 20
Метод Clone() в Java
В этом посте будет обсуждаться, как скопировать объект в Java с помощью clone() метод в Object class и один, предоставленный Apache Commons Lang. Мы также подробно обсудим мелкое и глубокое копирование.
Клонирование объекта создает копию существующего объекта для изменения или перемещения скопированного объекта, не затрагивая исходный объект. В Java управление объектами осуществляется с помощью ссылочных переменных, и нет оператора для фактического копирования объекта. Помните, что оператор присваивания дублирует ссылку, а не объект.
1. Использование Object.clone() метод
Классы, которым нужна функция копирования, могут использовать Object.clone() метод, который создает и возвращает копию объекта. Прототип Object.clone() является
В качестве возвращаемого типа Object.clone() является Object , приведение типов необходимо для присвоения возвращаемой ссылки Object ссылке на объект.
Все задействованные классы должны реализовывать Cloneable интерфейс для указания Object.clone() метод о том, что для этого метода разрешено создавать полевые копии экземпляров этого класса. Вызов метода clone объекта для экземпляра, который не реализует Cloneable интерфейс приводит к CloneNotSupportedException .
Поскольку каждый класс неявно расширяет Object учебный класс, Object.clone() является переопределяемым методом. Поскольку Java поддерживает ковариантные возвращаемые типы, возвращаемый тип clone() можно изменить с Object на тип клонируемого объекта, и clone() должен переопределить защищенный Object.clone() метод с общедоступным методом.
The clone() ведет себя так же, как Копировать конструктор. Он называет clone() метод своего родительского класса для получения копии и т. д., пока он в конечном итоге не достигнет класса Object. clone() метод, который создает новый экземпляр того же класса, поскольку объект копирует все поля в новый экземпляр.
1. Object.clone() не будет работать с интерфейсами и абстрактными классами.
Единственный способ использовать Object.clone() метод, если класс объекта известен, т. е. мы не можем получить доступ к clone() метод для абстрактного типа, так как большинство интерфейсов и абстрактных классов в Java не определяют общедоступный clone() метод.
Например, нельзя вызвать clone() в ссылке на карту в Java, потому что карта не указывает общедоступного clone() метод. Только реализации карты, такие как HashMap а также LinkedHashMap имеют clone() методы, но носить с собой тип класса объекта не рекомендуется, и это противоречит принципу “программа для интерфейса, а не для реализации”.
2. Реализация по умолчанию Object.clone() метод возвращает Неглубокое копирование.
При неглубоком копировании, если значение поля является примитивным типом, оно копирует свое значение; в противном случае, если значение поля является ссылкой на объект, оно копирует ссылку и, следовательно, ссылается на тот же объект. Теперь, если один из этих объектов изменен, изменение будет видно в другом. В Глубокое копирование, в отличие от мелкой копии, объекты, на которые есть ссылки, не являются общими; вместо этого новые объекты создаются для любых объектов, на которые есть ссылки.
Следующая программа демонстрирует использование Object.clone() метод, используя его реализацию по умолчанию, которая возвращает поверхностную копию. Мы рассмотрим глубокое копирование с помощью clone() метод в следующем разделе.
Java: Copying Objects
Unlike C++ and JavaScript, there’s no easy and direct way of copying objects. The built-in clone capability is poorly designed and is rarely the best alternative.
This article lists the pros and cons of all the common approaches, with examples.
- Copy Constructors
- Copy Factory Methods
- Serialization
- Cloning
- Copy methods
- Builders
Copy Constructors
public class Car < private String make; private int doors; private Motor motor; private Gearbox gearbox; public Car(Car other) < this.make = other.make; this.doors = other.doors; this.motor = other.motor; this.gearbox = other.gearbox; > … >
Car copy = new Car(original);
Note that this produces a shallow copy. (See Shallow vs Deep Copy, with examples.) If you do original.getGearbox().setGear(4) , then copy ‘s gear will change as well. To get a deep copy, change to…
… public Car(Car other) < this.make = other.make; this.doors = other.doors; this.motor = new Motor(other.motor); this.gearbox = new Gearbox(other.gearbox); > …
Copy Constructors and Inheritance
Adding a subclass, Taxi is straight forward:
public class Taxi extends Car < boolean isAvailable; public Taxi(Taxi other) < // Invoke copy constructor of Car super(other); this.isAvailable = other.isAvailable; > … >
However, when using a copy constructor you must know the actual runtime type. If you’re not careful, you may inadvertently create a Car when trying to create a copy of a Taxi .
Car copy = new Car(someCar); // What if someCar is a Taxi?!
You could use instanceof (often considered bad practice) or the visitor pattern to sort it out, but in this case you’re probably better off using one of the other techniques described in this article.
Pros
- Simple and straight forward
- Easy to get right, debug and maintain
- No casts required
Cons
Copy Factory Methods
A copy factory method encapsulates the object copying logic and provides finer control over the process. In the example below, this capability is used to tacle the problem of inheritance mentioned in the previous section.
public class CarFactory < … public Car copyOf(Car c) < Classcls = c.getClass(); if (cls == Car.class) < return new Car( c.make, c.doors, c.motor, c.gearbox); > if (cls == Taxi.class) < return new Taxi( c.make, c.doors, c.motor, c.gearbox, ((Taxi) c).isAvailable); > if (cls == Ambulance.class) < return new Ambulance( c.make, c.doors, c.motor, c.gearbox, ((Ambulance) c).beaconsOn); > throw new IllegalArgumentException("Can't copy car of type " + cls); > … >
Car copy = myCarFactory.copyOf(car);
Pros
Cons
- Another level of indirection
- Not as easy to extend
- Might require access to internal state
Serialization / Deserialization
By serializing an object into a byte array, then deserializing the byte array back into an object, you end up with a deep copy of the original.
// Serialize to byte[] ByteArrayOutputStream os = new ByteArrayOutputStream(); new ObjectOutputStream(os).writeObject(original); byte[] buf = os.toByteArray(); // Deserialize back into a Car object ByteArrayInputStream is = new ByteArrayInputStream(buf); Car copy = (Car) new ObjectInputStream(is).readObject();
With Apache Commons Lang the whole snippet can be replaced by…
…which does not throw any checked exceptions and infers the correct return type.
Note that the serialization mechanism does not call any constructors. Customizing the serialization / deserialization—which is needed when dealing with non-serializable external classes—requires you to «override» private methods. This kind of unintuitive semantics makes it tricker to understand, debug, and maintain code.
Pros
- Handles inheritance
- Very little boilerplate
- Provides deep copying out of the box
- Even object graphs with cycles!
Cons
- All objects must be Serializable
- Requires extra temporary memory
- Relies on black magic
- Overriding private methods
- No constructor calls
That being said, any serialization library would do. If you already have for example Jackson or Gson set up, you can reuse your ObjectMapper or Gson objects for copying purposes, and do away without «black magic» and casts.
Object.clone
Object.clone offers a shortcut for creating exact, field-by-field, copies of objects. A lot of the boilerplate otherwise required in copy constructors or static factory methods goes away.
class Car implements Cloneable < private String make; private int doors; private Motor motor; private Gearbox gearbox; … @Override public Car clone() < try < Car c = (Car) super.clone(); // Already copied by Object.clone // c.doors = doors; c.motor = motor.clone(); c.gearbox = gearbox.clone(); // No need to clone immutable objects // c.make = make; return c; > catch (CloneNotSupportedException e) < // Will not happen in this case return null; > > … >
Car copy = (Car) originalCar.clone();
Unfortunately the cloning API is poorly designed and should almost always be avoided. Copying arrays is a notable exception where cloning is the preferred method.
Pros
Cons
- Casts required
- No constructors called
- Incompatible with final fields
- CloneNotSupported is checked
- Can’t opt out from being Cloneable
Simple copy method
class Car < … public Car copy() < Car copy = new Car(); copy.make = this.make; copy.doors = this.doors; copy.motor = this.motor.copy(); copy.gearbox = this.gearbox.copy(); return copy; > … >
As it stands, it’s not easy to add a subclass to the above example. If a subclass, say Taxi , where to override Car.copy , it would need to call super.copy() to make sure private fields in Car are copied. super.copy() however, would return a Car object, which would be of little use to Taxi.copy since it needs to return a Taxi object.
If your situation involves a class hierarchy, a better solution would be:
class Car < … protected void copyFrom(Car car) < this.make = car.make; this.doors = car.doors; this.motor = car.motor; this.gearbox = car.gearbox; > public Car copy() < Car copy = new Car(); copy.copyFrom(this); return copy; > … > class Taxi extends Car < … protected void copyFrom(Taxi taxi) < super.copyFrom(taxi); this.isAvailable = taxi.isAvailable; > public Taxi copy() < Taxi copy = new Taxi(); copy.copyFrom(this); return copy; > … >
In the above example, the public copy method delegates to the protected copyFrom method which can easily be overridden in subclasses.
Pros
- Simple and straight forward
- Easy to understand and debug
- No casts required
- Don’t need to know the runtime type
Cons
Builders
If the class has a builder, you could add a from method that initiates the builder with the values from a given object.
class Car < public static class Builder < private String make; private int doors; … public Builder() < >public Builder make(String make) < this.make = make; return this; > // other builder methods… public Builder from(Car toCopyFrom) < make(toCopyFrom.make); doors(toCopyFrom.doors); … return this; > public Car build() < return new Car( make, doors, buildMotor(), buildGearbox()); > > // Rest of Car class … >
Car copy = new Car.Builder() .from(original) .build();
This is precisely what the Immutables library does when generating a builder for value classes.
Pros
Cons