浅拷贝:在堆中创建了一个新对象,将原对象的字段值复制到新对象中,如果原对象中有引用类型字段,会直接复制引用到新对象中,原对象和新对象的引用类型属性指向同一块内存地址。
class Stu implements Cloneable{
private int id;
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class MyClass implements Cloneable{
private int a;
private Stu s;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public Stu getS() {
return s;
}
public void setS(Stu s) {
this.s = s;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
MyClass c1 = new MyClass ();
MyClass c2 = (MyClass) c1.clone();
System.out.println(c1.getA() == c2.getA()); //true
System.out.println(c1.getS() == c2.getS()); //true
}
}
- MyClass中包含Stu引用类型属性,MyClass类实现了Cloneable接口,并重写了clone方法,内部是直接调用父类Object的clone()方法。
- 只是浅拷贝,并没有将MyClass中的引用类型属性拷贝一份,而是直接复制了原来的引用地址
深拷贝:将所有属性都拷贝一份,包括引用类型,原对象和新对象不会共享引用,新对象是一个全新的对象。
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
MyClass2 c1 = new MyClass2();
c1.setS(new Stu());
MyClass2 c2 = (MyClass2) c1.clone();
System.out.println(c1.getA() == c2.getA()); //true
System.out.println(c1.getS() == c2.getS()); //false
}
}
class MyClass2 implements Cloneable{
private int a;
private Stu s;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public Stu getS() {
return s;
}
public void setS(Stu s) {
this.s = s;
}
@Override
protected Object clone() throws CloneNotSupportedException {
MyClass2 c = (MyClass2) super.clone();
c.s = (Stu) s.clone();
return c;
}
}
class Stu implements Cloneable{
private int id;
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
- 修改了MyClass的clone方法实现,将引用类型属性也拷贝一份再赋给新对象,这样就是一个全新的对象了。(引用属性类也要实现Cloneable接口)
- 这时c1.getS() == c2.getS()结果为false,证明了原对象和新对象的引用指向不同。
对于实现深拷贝的方式,还有序列化和反序列,手动递归复制等方式。