深拷贝和浅拷贝的区别
浅拷贝:
只复制原对象的基本数据类型字段,拥有相对独立的副本数据,修改时不会影响到原对象的字段值。对于原对象的引用数据类型字段,直接共享原对象字段的引用,修改自己的字段时会同时影响原对象。
深拷贝:
对于基本数据类型,与浅拷贝一致,而对于引用数据类型字段,则使用递归(引用类型字段内部可能也有引用类型字段)将原对象的所有引用类型字段的内容也复制一份,以此保证两个对象的修改操作不会影响对方。
实现深拷贝的三种方法:
1、实现 Cloneable 接口并重写 clone() 方法:
前提:对象的所有引用数据类型,都需要重写clone()方法。对象在 clone() 方法中,通过递归克隆引用类型字段来实现深拷贝。clone()方法默认实现浅拷贝,想实现深拷贝需要先获得浅拷贝后的对象,再调用引用类型字段的clone()方法获取浅拷贝后的对象。(如果引用类型字段还有引用类型字段则重复此操作,直到只有基本数据类型字段)。实质上就是先拷贝最底层的引用类型字段,再逐步赋值并拷贝上层的引用类型字段,直到获取我们需要的对象。
class Professor implements Cloneable {String name;@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();//默认浅拷贝操作,如果该类也有引用类型字段则类似于Student的操作递归实现浅拷贝——深拷贝字段赋值,直到引用类型字段内部只有基本数据类型为止}
}
class Student implements Cloneable {Professor p;@Overridepublic Object clone() throws CloneNotSupportedException {Student cloned = (Student) super.clone();// 先浅拷贝当前对象cloned.p = (Professor) this.p.clone(); // 深拷贝引用类型字段并赋值return cloned;}
}
2、序列化和反序列化原对象
前提:对象的所有引用数据类型都应该实现Serilizable接口。通过序列化和反序列化原对象,并使用新对象接收返回值。当一个对象被序列化和反序列化后,默认创建新的引用类型对象进行字段的赋值,达到深拷贝的效果。
3、手动递归复制:
类似于重写clone()方法,在进行深拷贝时,通过调用引用数据类型字段的自定义的深拷贝方法手动创建新对象赋值到引用数据类型字段中。
class MyClass {private String field1;private NestedClass nestedObject;public MyClass deepCopy() {MyClass copy = new MyClass();copy
.setField1(this.field1);copy
.setNestedObject(this.nestedObject.deepCopy());return copy;}
}class NestedClass {private int nestedField;public NestedClass deepCopy() {NestedClass copy = new NestedClass();copy
.setNestedField(this.nestedField);return copy;}
}