对象内有多个对象型的成员变量如何实现深克隆?

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

在这里插入图片描述

深克隆有两种实现方式:

1)基于浅克隆的基础上通过覆盖Object类的clone()方法实现。

为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:

复制代码
1 package abc;
2
3 class Address implements Cloneable {
4 private String add;
5
6 public String getAdd() {
7 return add;
8 }
9
10 public void setAdd(String add) {
11 this.add = add;
12 }
13
14 @Override
15 public Object clone() {
16 Address addr = null;
17 try{
18 addr = (Address)super.clone();
19 }catch(CloneNotSupportedException e) {
20 e.printStackTrace();
21 }
22 return addr;
23 }
24 }
25
26 class Student implements Cloneable{
27 private int number;
28
29 private Address addr;
30
31 public Address getAddr() {
32 return addr;
33 }
34
35 public void setAddr(Address addr) {
36 this.addr = addr;
37 }
38
39 public int getNumber() {
40 return number;
41 }
42
43 public void setNumber(int number) {
44 this.number = number;
45 }
46
47 @Override
48 public Object clone() {
49 Student stu = null;
50 try{
51 stu = (Student)super.clone(); //浅复制
52 }catch(CloneNotSupportedException e) {
53 e.printStackTrace();
54 }
55 stu.addr = (Address)addr.clone(); //深度复制
56 return stu;
57 }
58 }
59 public class Test {
60
61 public static void main(String args[]) {
62
63 Address addr = new Address();
64 addr.setAdd(“杭州市”);
65 Student stu1 = new Student();
66 stu1.setNumber(123);
67 stu1.setAddr(addr);
68
69 Student stu2 = (Student)stu1.clone();
70
71 System.out.println(“学生1:” + stu1.getNumber() + “,地址:” + stu1.getAddr().getAdd());
72 System.out.println(“学生2:” + stu2.getNumber() + “,地址:” + stu2.getAddr().getAdd());
73
74 addr.setAdd(“西湖区”);
75
76 System.out.println(“学生1:” + stu1.getNumber() + “,地址:” + stu1.getAddr().getAdd());
77 System.out.println(“学生2:” + stu2.getNumber() + “,地址:” + stu2.getAddr().getAdd());
78 }
79 }
复制代码
结果:

学生1:123,地址:杭州市
学生2:123,地址:杭州市
学生1:123,地址:西湖区
学生2:123,地址:杭州市
2)通过序列化(Serialization)的方式(可解决多层克隆的问题)。

如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

Java语言提供的Cloneable接口和Serializable接口的代码非常简单,它们都是空接口,这种空接口也称为标识接口,标识接口中没有任何方法的定义,其作用是告诉JRE这些接口的实现类是否具有某个功能,如是否支持克隆、是否支持序列化等

public class Student implements Serializable{
private String name;
public Address address;
 //Discription:[深度复制方法,需要对象及对象所有的对象属性都实现序列化] 
public Student myclone() {
Student stu = null;
try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
      // 将流序列化成对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
stu = (Student) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return stu;
}
}
Address也必须实现Serializable,否则无法序列化
public class Address implements Serializable{
private String add;

public Address(String add) {
this.add= add;
}

}
将不需要序列化的属性前添加关键字 transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

被修饰static的属性也不可以序列化 ,序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量。

总结
实现对象克隆有两种方式:

1). 实现Cloneable接口并重写Object类中的clone()方法;

2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

注意

基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值