clone()
方法提供此功能。clone()
方法完成的。让我们看看它是如何完成的。Cloneable
接口。clone()
Object 类中的方法。[有点奇怪。clone()
方法应该在Cloneable
接口中。]/*
Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
The general intent is that, for any object x, the expression:
1) x.clone() != x will be true
2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
3) x.clone().equals(x) will be true, this is not an absolute requirement.
*/
protected native Object clone() throws CloneNotSupportedException;
Employee
具有 3 个属性的类 - id
、name
和department
。 Department
class 有两个属性 -id
和name
.
public class Employee implements Cloneable{
private int empoyeeId;
private String employeeName;
private Department department;
public Employee(int id, String name, Department dept)
{
this.empoyeeId = id;
this.employeeName = name;
this.department = dept;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
//Getters and Setters
}
$title(Department.java)
public class Department
{
private int id;
private String name;
public Department(int id, String name)
{
this.id = id;
this.name = name;
}
//Getters and Setters
}
所以,如果我们需要克隆 Employee 类,那么我们需要做这样的事情。
$title(TestCloning.java)
public class TestCloning
{
public static void main(String[] args) throws CloneNotSupportedException
{
Department dept = new Department(1, "Human Resource");
Employee original = new Employee(1, "Admin", dept);
//Lets create a clone of original object
Employee cloned = (Employee) original.clone();
//Let verify using employee id, if cloning actually workded
System.out.println(cloned.getEmpoyeeId());
//Verify JDK's rules
//Must be true and objects must have different memory addresses
System.out.println(original != cloned);
//As we are returning same class; so it should be true
System.out.println(original.getClass() == cloned.getClass());
//Default equals method checks for references so it should be false. If we want to make it true,
//then we need to override equals method in Employee class.
System.out.println(original.equals(cloned));
}
}
Output:
1
true
true
false
太好了,我们成功克隆了Employee
对象。但是,请记住我们有两个对同一个对象的引用,现在这两个引用都会在应用程序的不同部分更改对象的状态。想看看怎么样?让我们来看看。
public class TestCloning {
public static void main(String[] args) throws CloneNotSupportedException {
Department hr = new Department(1, "Human Resource");
Employee original = new Employee(1, "Admin", hr);
Employee cloned = (Employee) original.clone();
//Let change the department name in cloned object and we will verify in original object
cloned.getDepartment().setName("Finance");
System.out.println(original.getDepartment().getName());
System.out.println(cloned.getDepartment().getName());
}
}
Output:
Finance
Finance
clone
方法中,如果您没有克隆所有对象类型(不是基元),那么您正在制作一个浅拷贝。Department
在Employee
类的clone
方法上克隆对象。现在,我将进入下一节,我们将看到深度克隆。在大多数情况下,深度克隆是所需的行为。在深拷贝中,我们创建了一个独立于原始对象的克隆,并且在克隆对象中进行更改不应影响原始对象。
//Modified clone() method in Employee class
@Override
protected Object clone() throws CloneNotSupportedException {
Employee cloned = (Employee)super.clone();
cloned.setDepartment((Department)cloned.getDepartment().clone());
return cloned;
}
让我们看看在 Java 中是如何创建深拷贝的。 我修改了Employee
classesclone()
方法并clone
在Department
class 中添加了以下方法。
$title(Department.java)
//Defined clone method in Department class.
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public class TestCloning
{
public static void main(String[] args) throws CloneNotSupportedException
{
Department hr = new Department(1, "Human Resource");
Employee original = new Employee(1, "Admin", hr);
Employee cloned = (Employee) original.clone();
//Let change the department name in cloned object and we will verify in original object
cloned.getDepartment().setName("Finance");
System.out.println(original.getDepartment().getName());
System.out.println(cloned.getDepartment().getName());
}
}
Output:
Human Resource
Finance
super.clone()
所有成员类。复制构造函数是类中的特殊构造函数,它为自己的类类型接受参数。因此,当您将类的实例传递给复制构造函数时,构造函数将返回一个新的类实例,其值是从参数 instance 复制的。它可以帮助您使用 Cloneable界面克隆对象。
让我们在示例中看到这一点:
PointOne.java
public class PointOne
{
private Integer x;
private Integer y;
public PointOne(PointOne point){
this.x = point.x;
this.y = point.y;
}
}
这个方法看起来很简单,直到继承。当您通过扩展上面的类来定义一个类时,您还需要在那里定义一个类似的构造函数。在子类中,您需要复制子特定属性并将参数传递给超类的构造函数。让我们看看如何?
PointTwo.java
public class PointTwo extends PointOne
{
private Integer z;
public PointTwo(PointTwo point){
super(point); //Call Super class constructor here
this.z = point.z;
}
}
那么,我们现在还好吗?不。继承的问题在于准确的行为只能在运行时识别。所以,在我们的例子中,如果某个类通过了PointTwo
in 的构造函数的实例PointOne
。PointOne
传递实例的PointTwo
作为回报的实例。让我们在代码中看到这一点:
Test.java
class Test
{
public static void main(String[] args)
{
PointOne one = new PointOne(1,2);
PointTwo two = new PointTwo(1,2,3);
PointOne clone1 = new PointOne(one);
PointOne clone2 = new PointOne(two);
//Let check for class types
System.out.println(clone1.getClass());
System.out.println(clone2.getClass());
}
}
Output:
class corejava.cloning.PointOne
class corejava.cloning.PointOne
创建复制构造函数的另一种方法是使用静态工厂方法。它们采用类类型作为参数,并使用该类的另一个构造函数创建一个新实例。然后这些工厂方法会将所有状态数据复制到上一步刚刚创建的新类实例中,并返回这个更新后的实例。
PointOne 带复制方法
public class PointOne implements Cloneable
{
private Integer x;
private Integer y;
public PointOne(Integer x, Integer y)
{
this.x = x;
this.y = y;
}
public PointOne copyPoint(PointOne point) throws CloneNotSupportedException
{
if(!(point instanceof Cloneable))
{
throw new CloneNotSupportedException("Invalid cloning");
}
//Can do multiple other things here
return new PointOne(point.x, point.y);
}
}
6. 带序列化的Java深拷贝
序列化是另一种深度克隆的简单方法。在此方法中,您只需序列化要克隆的对象并对其进行反序列化。显然,需要克隆的对象应该实现Serializable
接口。clone()
方法贵一百倍。Serializable
.Serializable
很棘手,并不是所有的类都可以依靠它来做对
@SuppressWarnings("unchecked")
public static T clone(T t) throws Exception {
//Check if T is instance of Serializeble other throw CloneNotSupportedException
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//Serialize it
serializeToOutputStream(t, bos);
byte[] bytes = bos.toByteArray();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
//Deserialize it and return the new instance
return (T)ois.readObject();
}
在Apache commons 中,SerializationUtils
类也有用于深度克隆的实用功能。如果您有兴趣,请关注他们的官方文档。
pom.xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
SerializationUtils 示例
SomeObject cloned = org.apache.commons.lang.SerializationUtils.clone(someObject);
clone()
特定类的方法,因为不确定该类中是否实现了该方法时,可以检查该类是否为“ Cloneable
”接口的实例,如下所示。if(obj1 instanceof Cloneable){
obj2 = obj1.clone();
}
//Dont do this. Cloneable dont have any methods
obj2 = (Cloneable)obj1.clone();
https://www.leftso.com/article/889.html