浅克隆和深克隆

有两种方式:

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

2.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正意义上的深度克隆,代码如下:

 1 package com.lovo;  
 2   
 3 import java.io.ByteArrayInputStream;  
 4 import java.io.ByteArrayOutputStream;  
 5 import java.io.ObjectInputStream;  
 6 import java.io.ObjectOutputStream;  
 7   
 8 public class MyUtil {  
 9   
10     private MyUtil() {  
11         throw new AssertionError();  
12     }  
13   
14     public static <T> T clone(T obj) throws Exception {  
15         ByteArrayOutputStream bout = new ByteArrayOutputStream();  
16         ObjectOutputStream oos = new ObjectOutputStream(bout);  
17         oos.writeObject(obj);  
18   
19         ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());  
20         ObjectInputStream ois = new ObjectInputStream(bin);  
21         return (T) ois.readObject();  
22           
23         // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义  
24         // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源  
25     }  
26 }  

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

 

 1 package com.lovo;  
 2   
 3 import java.io.ByteArrayInputStream;  
 4 import java.io.ByteArrayOutputStream;  
 5 import java.io.ObjectInputStream;  
 6 import java.io.ObjectOutputStream;  
 7   
 8 public class MyUtil {  
 9   
10     private MyUtil() {  
11         throw new AssertionError();  
12     }  
13   
14     public static <T> T clone(T obj) throws Exception {  
15         ByteArrayOutputStream bout = new ByteArrayOutputStream();  
16         ObjectOutputStream oos = new ObjectOutputStream(bout);  
17         oos.writeObject(obj);  
18   
19         ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());  
20         ObjectInputStream ois = new ObjectInputStream(bin);  
21         return (T) ois.readObject();  
22           
23         // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义  
24         // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源  
25     }  
26 }  

 

假克隆:

               通过赋值符号 = 对对象赋值实现;

实现浅克隆:

当需要克隆对象成员变量是基本类型,使用浅克隆可以实现;如果成员变量包括可变的引用类型,则需要深度克隆;

PS:如果引用类型是String等不可变的类型,则不必深度克隆;

 

需要克隆对象时候,需要调用clone() 方法;该方法的申明:

 

Protected Object clone() throws CloneNotSupportedException

 

需要注意是该方法是保护类型的,需要继承Cloneable接口,重写该方法并且修改访问权限为public;

如果类中包含引用类型域,浅克隆就会出现CloneSupportedException 异常;

浅克隆事例:

 

 

 1 package com.JunitTest.www;
 2 
 3 
 4 public class Address {
 5     private String state;
 6     private String province;
 7     private String city;
 8 
 9     public Address(String state, String province, String city) {
10         super();
11         this.state = state;
12         this.province = province;
13         this.city = city;
14     }
15 
16     public String getState() {
17         return state;
18     }
19 
20     public void setState(String state) {
21         this.state = state;
22     }
23 
24     public String getProvince() {
25         return province;
26     }
27 
28     public void setProvince(String province) {
29         this.province = province;
30     }
31 
32     public String getCity() {
33         return city;
34     }
35 
36     public void setCity(String city) {
37         this.city = city;
38     }
39 
40     @Override
41     public String toString() {
42         StringBuilder sBuilder = new StringBuilder();
43         sBuilder.append("国家:" + state + ",");
44         sBuilder.append("省:" + province + ",");
45         sBuilder.append("市:" + city + ",");
46         return sBuilder.toString();
47     }
48 
49 }

 

 1 package com.JunitTest.www;
 2 
 3 public class Employee implements Cloneable {
 4     private String name;
 5     private int age;
 6     private Address address;
 7 
 8     public Employee(String name, int age, Address address) {
 9         super();
10         this.name = name;
11         this.age = age;
12         this.address = address;
13     }
14 
15     public String getName() {
16         return name;
17     }
18 
19     public void setName(String name) {
20         this.name = name;
21     }
22 
23     public int getAge() {
24         return age;
25     }
26 
27     public void setAge(int age) {
28         this.age = age;
29     }
30 
31     public Address getAddress() {
32         return address;
33     }
34 
35     public void setAddress(Address address) {
36         this.address = address;
37     }
38 
39     @Override
40     public String toString() {
41         return "Employee [name=" + name + ", age=" + age + ", address=" + address + "]";
42     }
43 
44     @Override
45     protected Employee clone() throws CloneNotSupportedException {
46         Employee employee = null;
47         try {
48             employee = (Employee) super.clone();
49         } catch (CloneNotSupportedException exception) {
50             exception.printStackTrace();
51         }
52         return employee;
53     }
54 }

测试代码:

 1 package com.JunitTest.www;
 2 
 3 public class Test001 {
 4     public static void main(String[] args) throws CloneNotSupportedException {
 5         System.out.println("克隆之前:");
 6         Address address = new Address("中国", "四川", "成都");
 7         Employee employee1 = new Employee("张三丰", 12, address);
 8         System.out.println("员工1的信息");
 9         System.out.println(employee1);
10         System.out.println("克隆之后");
11         Employee employee2 = employee1.clone();
12         employee2.getAddress().setState("中国");
13         employee2.getAddress().setProvince("四川");
14         employee2.getAddress().setCity("成都");
15         employee2.setName("屈耕");
16         employee2.setAge(24);
17         System.out.println("员工1 的信息");
18         System.out.println(employee1);
19         System.out.println("员工2的信息");
20         System.out.println(employee2);
21     }
22 }

输出信息:

克隆之前:
员工1的信息
Employee [name=张三丰, age=12, address=国家:中国,省:四川,市:成都,]
克隆之后
员工1 的信息
Employee [name=张三丰, age=12, address=国家:中国,省:四川,市:成都,]
员工2的信息
Employee [name=屈耕, age=24, address=国家:中国,省:四川,市:成都,]

深度克隆:

 1 package com.deepClone.www;
 2 
 3 /**
 4  * Ps:因为Address类的域不是基本变量就是不可变类型 ,所以直接使用浅克隆即可
 5  * 
 6  * @author Administrator
 7  *
 8  */
 9 public class Address implements Cloneable {
10     private String state; // 员工所在国家
11     private String province; // 员工所在省份
12     private String city; // 员工所在城市
13 
14     /**
15      * 构造方法初始化
16      * 
17      * @param state
18      * @param province
19      * @param city
20      */
21     public Address(String state, String province, String city) {
22         super();
23         this.state = state;
24         this.province = province;
25         this.city = city;
26     }
27  
28     public String getState() {
29         return state;
30     }
31 
32     public void setState(String state) {
33         this.state = state;
34     }
35 
36     public String getProvince() {
37         return province;
38     }
39 
40     public void setProvince(String province) {
41         this.province = province;
42     }
43 
44     public String getCity() {
45         return city;
46     }
47 
48     public void setCity(String city) {
49         this.city = city;
50     }
51 
52     /**
53      * 实现浅克隆
54      * 
55      * @return
56      * @throws CloneNotSupportedException
57      */
58     @Override
59     protected Object clone() throws CloneNotSupportedException {
60         Address address = null;
61         try {
62             address = (Address) super.clone();
63         } catch (Exception e) {
64             e.printStackTrace();
65         }
66         return address;
67     }
68 
69     /**
70      * 重写toString()方法
71      * 
72      * @return
73      */
74     @Override
75     public String toString() {
76         return "Address [国家=" + state + ", 省=" + province + ", 市=" + city + "]";
77     }
78 
79 }

新建Employee类并且实现Cloneable接口:

 1 package com.deepClone.www;
 2 
 3 public class Employee implements Cloneable {
 4     private String name;// 员工姓名
 5     private int age;// 员工年龄
 6     private Address address;// 员工地址
 7 
 8     // 构造函数实现初始化
 9     public Employee(String name, int age, Address address) {
10         super();
11         this.name = name;
12         this.age = age;
13         this.address = address;
14     }
15 
16     public String getName() {
17         return name;
18     }
19 
20     public void setName(String name) {
21         this.name = name;
22     }
23 
24     public int getAge() {
25         return age;
26     }
27 
28     public void setAge(int age) {
29         this.age = age;
30     }
31 
32     public Address getAddress() {
33         return address;
34     }
35 
36     public void setAddress(Address address) {
37         this.address = address;
38     }
39 
40     // 重写Clone() 实现深度克隆
41     @Override
42     protected Object clone() throws CloneNotSupportedException {
43         Employee employee = null;
44         try {
45             employee = (Employee) super.clone();
46             employee.address = (Address) address.clone();
47         } catch (Exception e) {
48             e.printStackTrace();
49         }
50         return employee;
51     }
52 
53     // 重写toString()
54     @Override
55     public String toString() {
56         return "Employee [姓名=" + name + ", 年龄=" + age + ", 地址=" + address + "]";
57     }
58 
59 }

测试代码:

 1 package com.deepClone.www;
 2 
 3 public class Test001 {
 4     public static void main(String[] args) throws CloneNotSupportedException {
 5         System.out.println("克隆之前");
 6         Address address = new Address("中国", "四川", "广安");
 7         Employee employee = new Employee("夜雨梧桐", 25, address);
 8         System.out.println("员工1的信息");
 9         System.out.println(employee);
10         System.out.println("克隆之后");
11         Employee employee2 = (Employee) employee.clone();
12         employee2.getAddress().setState("中国");
13         employee2.getAddress().setProvince("四川");
14         employee2.getAddress().setCity("成都");
15         employee2.setName("强壮的男人");
16         employee2.setAge(26);
17         employee2.setAddress(address);
18         System.out.println("员工1的信息");
19         System.out.println(employee);
20         System.out.println("员工2的信息");
21         System.out.println(employee2);
22     }
23 }

显示效果:

1 克隆之前
2 员工1的信息
3 Employee [姓名=夜雨梧桐, 年龄=25, 地址=Address [国家=中国, 省=四川, 市=广安]]
4 克隆之后
5 员工1的信息
6 Employee [姓名=夜雨梧桐, 年龄=25, 地址=Address [国家=中国, 省=四川, 市=广安]]
7 员工2的信息
8 Employee [姓名=强壮的男人, 年龄=26, 地址=Address [国家=中国, 省=四川, 市=广安]]

但是问题来了,如果对象中的引用类型特别多,需要克隆Clone()就会相当复杂;也可以考虑序列化的方式实现克隆;

新建Address类并且实现Serializable接口:

 1 package com.CloneSerializeble.www;
 2 
 3 import java.io.Serializable;
 4 
 5 public class Address implements Serializable {
 6 
 7     /**
 8      * 
 9      */
10     private static final long serialVersionUID = -5531527688287881990L;
11     private String State;
12     private String Province;
13     private String City;
14 
15     public Address(String state, String province, String city) {
16         super();
17         State = state;
18         Province = province;
19         City = city;
20     }
21 
22     public String getState() {
23         return State;
24     }
25 
26     public void setState(String state) {
27         State = state;
28     }
29 
30     public String getProvince() {
31         return Province;
32     }
33 
34     public void setProvince(String province) {
35         Province = province;
36     }
37 
38     public String getCity() {
39         return City;
40     }
41 
42     public void setCity(String city) {
43         City = city;
44     }
45 
46     public static long getSerialversionuid() {
47         return serialVersionUID;
48     }
49 
50     @Override
51     public String toString() {
52 
53         return "Address [State=" + State + ", Province=" + Province + ", City=" + City + "]";
54     }
55 
56 }

实现Employee 实现Serializable接口:

 1 package com.CloneSerializeble.www;
 2 
 3 import java.io.Serializable;
 4 
 5 public class Employee implements Serializable {
 6 
 7     /**
 8      * 
 9      */
10     private static final long serialVersionUID = -3783147174978411726L;
11     private String name;
12     private int age;
13     private Address address;
14 
15     public Employee(String name, int age, Address address) {
16         super();
17         this.name = name;
18         this.age = age;
19         this.address = address;
20     }
21 
22     public String getName() {
23         return name;
24     }
25 
26     public void setName(String name) {
27         this.name = name;
28     }
29 
30     public int getAge() {
31         return age;
32     }
33 
34     public void setAge(int age) {
35         this.age = age;
36     }
37 
38     public Address getAddress() {
39         return address;
40     }
41 
42     public void setAddress(Address address) {
43         this.address = address;
44     }
45 
46     public static long getSerialversionuid() {
47         return serialVersionUID;
48     }
49 
50     @Override
51     public String toString() {
52         return "Employee [name=" + name + ", age=" + age + ", address=" + address + "]";
53     }
54 
55 }

测试代码:

 1 package com.CloneSerializeble.www;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.FileNotFoundException;
 5 import java.io.FileOutputStream;
 6 import java.io.IOException;
 7 import java.io.ObjectInputStream;
 8 import java.io.ObjectOutputStream;
 9 
10 /**
11  * 测试代码
12  * 
13  * @author Administrator
14  *
15  */
16 public class Test001 {
17     public static void main(String[] args) throws IOException {
18         System.out.println("序列化之前");
19         Address address = new Address("中国", "台湾", "台北");
20         Employee employee = new Employee("夜雨梧桐", 25, address);
21         System.out.println("员工1的信息");
22         System.out.println(employee);
23         System.out.println("序列化之后");
24         ObjectOutputStream outputStream = null;
25         ObjectInputStream inputStream = null;
26         Employee employee2 = null;
27         try {
28             outputStream = new ObjectOutputStream(new FileOutputStream("employee.dat"));
29             outputStream.writeObject(employee);
30             inputStream = new ObjectInputStream(new FileInputStream("employee.dat"));
31             employee2 = (Employee) inputStream.readObject();
32         } catch (FileNotFoundException e) {
33             e.printStackTrace();
34         } catch (IOException exception) {
35             exception.printStackTrace();
36         } catch (ClassNotFoundException e) {
37             e.printStackTrace();
38         } finally {
39             outputStream.close();
40             inputStream.close();
41         }
42         if (employee2 != null) {
43             employee2.getAddress().setState("中国");
44             employee2.getAddress().setProvince("四川");
45             employee2.getAddress().setCity("成都");
46             employee2.setName("刘伟");
47             employee2.setAge(19);
48             System.out.println("员工1的信息");
49             System.out.println(employee);
50             System.out.println("员工2的信息");
51             System.out.println(employee2);
52         }
53     }
54 }

显示结果:

1 序列化之前
2 员工1的信息
3 Employee [name=夜雨梧桐, age=25, address=Address [State=中国, Province=台湾, City=台北]]
4 序列化之后
5 员工1的信息
6 Employee [name=夜雨梧桐, age=25, address=Address [State=中国, Province=台湾, City=台北]]
7 员工2的信息
8 Employee [name=刘伟, age=19, address=Address [State=中国, Province=四川, City=成都]]

当然,也可以使用ByteArrayOutputStream和ByteInputStream将对象保存在内存中,就不必产生一个本地文件保存对象;

 

posted on 2015-10-19 17:50  夜雨梧桐  阅读(235)  评论(0编辑  收藏  举报

导航