Java 对象的克隆指的是创建一个与原始对象相同的新对象,但两个对象的引用地址是不同的。根据克隆的深度不同,可以分为浅克隆和深克隆两种。
浅克隆
浅克隆是指在克隆一个对象时,只复制对象中的基本类型数据和对象的引用地址,而不是复制对象中引用对象的内容。这意味着,克隆后的对象和原始对象共享引用对象,即对其中一个对象的更改会对另一个对象产生影响。
如何进行浅克隆
Java 中使用clone()方法来实现对象的浅克隆。需要注意,被克隆的对象必须实现 Cloneable 接口,并且重写 clone() 方法。示例如下:
public class MyObject implements Cloneable {
private int id;
private String name;
private Date createTime;
public MyObject(int id, String name, Date createTime) {
this.id = id;
this.name = name;
this.createTime = createTime;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
MyObject obj1 = new MyObject(1, "Object1", new Date());
MyObject obj2 = (MyObject) obj1.clone();
System.out.println("obj1:" + obj1);
System.out.println("obj2:" + obj2);
System.out.println("obj1 == obj2:" + (obj1 == obj2)); // false
}
}
以上示例中,MyObject 类实现了 Cloneable 接口,并重写了 clone() 方法。在 main() 方法中,创建了一个原始对象 obj1,然后通过调用 clone() 方法创建 obj2。输出结果表明,obj1 和 obj2 的引用地址不同,即克隆是成功的。
浅克隆的示例说明
示例还是以上面的 MyObject 类为例。在浅克隆中,obj1 和 obj2 中的 createTime 属性存储的是同一个 Date 对象的引用,即两个对象共享一个 Date 对象,因此如果修改 obj1 中的 createTime 属性,则 obj2 中的 createTime 属性也会受到影响。示例如下:
public static void main(String[] args) throws CloneNotSupportedException {
MyObject obj1 = new MyObject(1, "Object1", new Date());
MyObject obj2 = (MyObject) obj1.clone();
obj1.getCreateTime().setTime(11111111); // 修改 createTime 属性
System.out.println("obj1:" + obj1);
System.out.println("obj2:" + obj2);
}
输出结果如下:
obj1:MyObject(id=1, name=Object1, createTime=Wed Jan 01 08:53:31 CST 1970)
obj2:MyObject(id=1, name=Object1, createTime=Wed Jan 01 08:53:31 CST 1970)
可以看出,obj2 中的 createTime 属性也被修改了。
深克隆
深克隆是指在克隆一个对象时,不仅要复制对象中的基本类型数据和对象的引用地址,还要复制对象中引用对象的内容。这意味着,克隆后的对象和原始对象不共享引用对象,即对其中一个对象的更改不会对另一个对象产生影响。
如何进行深克隆
Java 实现深克隆的方式有很多,这里介绍其中两种方式:序列化和递归克隆。
序列化方式
序列化是将一个 Java 对象转化为字节流数据的过程。可以通过将对象序列化为字节流数据,再将字节流数据反序列化为新的对象来实现深克隆。示例如下:
public class MyObject implements Serializable {
private int id;
private String name;
private Date createTime;
public MyObject(int id, String name, Date createTime) {
this.id = id;
this.name = name;
this.createTime = createTime;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
MyObject obj1 = new MyObject(1, "Object1", new Date());
MyObject obj2 = (MyObject) ObjectUtils.deepClone(obj1);
obj1.getCreateTime().setTime(11111111); // 修改 createTime 属性
System.out.println("obj1:" + obj1);
System.out.println("obj2:" + obj2);
}
}
public class ObjectUtils {
// 深克隆方法
public static Object deepClone(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
在以上示例中,MyObject 类实现了 Serializable 接口。ObjectUtils 类中定义了一个静态的 deepClone() 方法,该方法接收一个对象作为参数,并返回一个与参数对象相同的新对象。在 main() 方法中,创建了一个原始对象 obj1,然后通过调用 deepClone() 方法创建了一个新的对象 obj2。输出结果表明,obj1 和 obj2 的引用地址不同且 createTime 属性不共享引用对象,即深度克隆成功。
递归克隆方式
递归克隆方式是指在进行深克隆的过程中,对于对象中的引用类型属性,递归调用克隆方法,直到将所有的引用对象都克隆出来。示例如下:
public class MyObject implements Cloneable {
private int id;
private String name;
private Date createTime;
private List<String> tags;
public MyObject(int id, String name, Date createTime, List<String> tags) {
this.id = id;
this.name = name;
this.createTime = createTime;
this.tags = tags;
}
@Override
protected Object clone() throws CloneNotSupportedException {
MyObject obj = (MyObject) super.clone();
obj.createTime = (Date) this.createTime.clone();
obj.tags = new ArrayList<>(this.tags);
return obj;
}
public static void main(String[] args) throws CloneNotSupportedException {
MyObject obj1 = new MyObject(1, "Object1", new Date(), Arrays.asList("tag1", "tag2"));
MyObject obj2 = (MyObject) obj1.clone();
obj1.getCreateTime().setTime(11111111); // 修改 createTime 属性
obj1.getTags().add("tag3"); // 修改 tags 属性
System.out.println("obj1:" + obj1);
System.out.println("obj2:" + obj2);
}
}
在以上示例中,MyObject 类中的 clone() 方法首先调用了 super.clone() 方法克隆了基本类型属性和 tags 属性(因为 List 属性是引用类型),然后对 createTime 属性进行了单独的深克隆。在 main() 方法中,创建了一个原始对象 obj1,然后通过调用 clone() 方法创建了一个新的对象 obj2。输出结果表明,obj1 和 obj2 的引用地址不同且 createTime 属性不共享引用对象,即深度克隆成功。
深克隆的示例说明
示例还是以上面的 MyObject 类为例。在深克隆中,obj1 和 obj2 中的 createTime 属性存储的是两个不同的 Date 对象,即两个对象不共享一个 Date 对象,因此如果修改 obj1 中的 createTime 属性,则 obj2 中的 createTime 属性不会受到影响。同时,obj1 和 obj2 中的 tags 属性也存储的是不同的 List 对象,即两个对象不共享一个 List 对象,因此如果修改 obj1 中的 tags 属性,则 obj2 中的 tags 属性也不会受到影响。示例如下:
public static void main(String[] args) throws CloneNotSupportedException {
MyObject obj1 = new MyObject(1, "Object1", new Date(), Arrays.asList("tag1", "tag2"));
MyObject obj2 = (MyObject) obj1.clone();
obj1.getCreateTime().setTime(11111111); // 修改 createTime 属性
obj1.getTags().add("tag3"); // 修改 tags 属性
System.out.println("obj1:" + obj1);
System.out.println("obj2:" + obj2);
}
输出结果如下:
obj1:MyObject(id=1, name=Object1, createTime=Wed Jan 01 08:53:31 CST 1970, tags=[tag1, tag2, tag3])
obj2:MyObject(id=1, name=Object1, createTime=Thu Sep 17 19:38:31 CST 1970, tags=[tag1, tag2])
可以看出,obj2 中的 createTime 属性和 tags 属性没有被修改。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java 对象的克隆(浅克隆和深克隆) - Python技术站