java进阶6 -「深浅拷贝」

浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。

深拷贝:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

 

一 demo演示

1 Professor类

 1 class Professor implements Serializable, Cloneable {
 2     private static final long serialVersionUID = 1286716519490813020L;
 3     public String name;
 4     public int age;
 5 
 6     // 构造函数是为了CloneUtils json序列化使用
 7     public Professor() {
 8     }
 9 
10     public Professor(String name, int age) {
11         this.name = name;
12         this.age = age;
13     }
14 
15     public Object clone() throws CloneNotSupportedException {
16         return super.clone();
17     }
18 }

 

2. Student类

 1 class Student implements Serializable, Cloneable {
 2     private static final long serialVersionUID = -547004870369127943L;
 3     public String name;
 4     public int age;
 5     public Professor p;
 6 
 7     // 构造函数是为了CloneUtils工具类clazz.instance()方法调用 & json序列化使用
 8     public Student() {
 9     }
10 
11     public Student(String name, int age, Professor p) {
12         this.name = name;
13         this.age = age;
14         this.p = p;
15     }
16 
17     public Object shallowClone() throws CloneNotSupportedException {
18         Student s = (Student) super.clone();
19         //s.p = (Professor) p.clone();  //这句加上就是深拷贝了
20         return s;
21     }
22 }

 

3 CloneUtils类

 1 @SuppressWarnings("unchecked")
 2 public class CloneUtils {
 3 
 4     /**
 5      * 浅拷贝
 6      */
 7     public static <T> T shallowClone(T t) {
 8         try {
 9             if (t == null) {
10                 return null;
11             }
12 
13             Class<? extends T> clazz = (Class<? extends T>) t.getClass();
14             T instance = clazz.newInstance();
15 
16             Field[] fields = clazz.getDeclaredFields();
17             if (fields != null) {
18                 for (Field field : fields) {
19                     int modifiers = field.getModifiers();
20                     if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) { //final的无法拷贝, static的无需拷贝
21                         continue;
22                     }
23                     field.setAccessible(true);
24                     field.set(instance, field.get(t));
25                 }
26             }
27             return instance;
28         } catch (Exception e) {
29             System.out.printf("error" + e);
30             // ignore
31         }
32         return null;
33     }
34 
35     /**
36      * 深拷贝
37      */
38     public static <T> T deepClone(T t, Class<T> clazz) throws IOException {
39         try {
40             if (t == null || clazz == null) {
41                 return null;
42             }
43             return JsonUtils.toBean(JsonUtils.toJson(t), clazz);
44         } catch (Exception e) {
45             System.out.printf("error" + e);
46             // ignore
47         }
48         return null;
49     }
50 }

 

4 Main

 1 class Main {
 2     public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
 3         Professor p = new Professor("教授1", 50);
 4         Student s1 = new Student("学生1", 18, p);
 5 //        Student s2 = (Student) s1.shallowClone();
 6 //        Student s2 = CloneUtils.shallowClone(s1);
 7         Student s2 = CloneUtils.deepClone(s1, Student.class);
 8         s2.p.name = "教授2";
 9         s2.p.age = 30;
10         s2.name = "学生2";
11         s2.age = 25;
12         System.out.println(s1.name + " " + s1.age + " " + s1.p.name + " " + s1.p.age);
13     }
14 }

 第5行输出结果:   学生1 18 教授2 30

 第6行输出结果:   学生1 18 教授2 30

 第7行输出结果:    学生1 18 教授1 50

 

二 分析

上面的shallow clone只是实体的所有数据&引用进行了简单拷贝,这样会出现修改拷贝类s2中的引用指针p时,会影响原始的实体s1.p,造成不可预知的错误

可以看到把Student类中的引用p也进行clone就是深拷贝了(Student#line19注释打开)

或者直接用序列化的方式进行深拷贝,深拷贝的原始实体和拷贝实体毫无关系,不会互相影响

 

 

(借用网上的一个图, Address为代指上文代码的Processor, Person代指上文的Student) 

 

posted @ 2018-01-03 11:33  balfish  阅读(452)  评论(1编辑  收藏  举报