1. Introduction
1.绪论
A copy constructor in a Java class is a constructor that creates an object using another object of the same Java class.
Java类中的复制构造函数是一个构造函数,它使用同一Java类的另一个对象创建一个对象。
That’s helpful when we want to copy a complex object that has several fields, or when we want to make a deep copy of an existing object.
当我们想复制一个有多个字段的复杂对象,或者想对现有对象进行深度复制时,这很有帮助。
2. How to Create a Copy Constructor
2.如何创建一个复制构造器
To create a copy constructor, we can first declare a constructor that takes an object of the same type as a parameter:
为了创建一个拷贝构造函数,我们可以首先声明一个构造函数,该构造函数需要一个相同类型的对象作为参数。
public class Employee {
private int id;
private String name;
public Employee(Employee employee) {
}
}
Then, we copy each field of the input object into the new instance:
然后,我们将输入对象的每个字段复制到新的实例中。
public class Employee {
private int id;
private String name;
public Employee(Employee employee) {
this.id = employee.id;
this.name = employee.name;
}
}
What we have here is a shallow copy, which is fine since all of our fields – an int and a String in this case – are either primitive types or immutable types.
我们在这里得到的是一个浅层拷贝,这很好,因为我们所有的字段–本例中的int 和String –要么是原始类型,要么是不可变类型。
If the Java class has mutable fields, then we can instead make a deep copy inside its copy constructor. With a deep copy, the newly created object is independent of the original one because we create a distinct copy of each mutable object:
如果Java类有易变的字段,那么我们可以在它的复制构造函数中制作一个deep copy。通过深度拷贝,新创建的对象是独立于原始对象的,因为我们为每个可变对象创建了一个不同的拷贝。
public class Employee {
private int id;
private String name;
private Date startDate;
public Employee(Employee employee) {
this.id = employee.id;
this.name = employee.name;
this.startDate = new Date(employee.startDate.getTime());
}
}
3. Copy Constructor vs. Clone
3.复制构造器与克隆
In Java, we can also use the clone method to create an object from an existing object. However, the copy constructor has some advantages over the clone method:
在Java中,我们也可以使用clone方法来从现有对象中创建一个对象。然而,与clone方法相比,复制构造函数有一些优势。
- The copy constructor is much easier to implement. We do not need to implement the Cloneable interface and handle CloneNotSupportedException.
- The clone method returns a general Object reference. Therefore, we need to typecast it to the appropriate type.
- We can not assign a value to a final field in the clone method. However, we can do so in the copy constructor.
4. Inheritance Issues
4.继承问题
Copy constructors in Java are not inheritable by subclasses. Therefore, if we try to initialize a child object from a parent class reference, we will face a casting issue when cloning it with the copy constructor.
Java中的复制构造函数是不能被子类继承的。因此,如果我们试图从父类的引用中初始化一个子对象,在用复制构造函数克隆它时,我们将面临一个铸造问题。
To illustrate this issue, let’s first create a subclass of Employee and its copy constructor:
为了说明这个问题,让我们首先创建一个Employee的子类及其复制构造函数。
public class Manager extends Employee {
private List<Employee> directReports;
// ... other constructors
public Manager(Manager manager) {
super(manager.id, manager.name, manager.startDate);
this.directReports = directReports.stream()
.collect(Collectors.toList());
}
}
Then, we declare an Employee variable and instantiate it with the Manager constructor:
然后,我们声明一个Employee变量,并用Manager构造函数将其实例化。
Employee source = new Manager(1, "Baeldung Manager", startDate, directReports);
Since the reference type is Employee, we have to cast it to Manager type so that we can use the copy constructor of the Manager class:
由于引用类型是Employee,我们必须将其转换为Manager类型,以便我们可以使用Manager类的复制构造函数。
Employee clone = new Manager((Manager) source);
We may get ClassCastException at runtime if the input object is not an instance of Manager class.
如果输入对象不是Manager类的实例,我们可能在运行时得到ClassCastException。
One way to avoid casting in the copy constructor is to create a new inheritable method for both classes:
避免在复制构造函数中铸造的一个方法是为两个类创建一个新的可继承方法。
public class Employee {
public Employee copy() {
return new Employee(this);
}
}
public class Manager extends Employee {
@Override
public Employee copy() {
return new Manager(this);
}
}
In each class method, we call its copy constructor with the input of this object. In this way, we can guarantee that the generated object equals the caller object:
在每个类方法中,我们用this对象的输入来调用其复制构造函数。通过这种方式,我们可以保证生成的对象等同于调用者的对象。
Employee clone = source.copy();
5. Conclusion
5.总结
In this tutorial, we showed how to create a copy constructor with some code examples. Also, we discussed several reasons why we should avoid the clone method.
在本教程中,我们通过一些代码实例展示了如何创建一个复制构造函数。此外,我们还讨论了我们应该避免使用clone方法的几个原因。
Copy constructor has a casting issue when we use it to clone a child class object whose reference type is the parent class. We provided one solution for this issue.
当我们使用复制构造函数来克隆一个引用类型为父类的子类对象时,有一个铸造问题。我们为这个问题提供了一个解决方案。
As always, the source code for the tutorial is available over on GitHub.
一如既往,该教程的源代码可在GitHub上获得over。