Java对象的复制——小明和他的克隆人的故事

2021-05-30  本文已影响0人  肥兔子爱豆畜子

Java对象的复制分为以下3种:

接下来用一个程序代码讲述一个故事,来加深一下深拷贝和浅拷贝的区别。而直接赋值太简单了,就不讲了。
故事是这样的,小明有个女朋友叫小美,小明有一天有了自己的克隆人,这个克隆人也叫小明,但是真正的小明显然是不想跟自己的克隆人共享女朋友的 -_- ,所以他试图将小丽介绍给克隆人当做女朋友,故事就是这样。。。
接下来看代码:

public class Boy implements Cloneable{
    private String name;
    private GirlFriend gf;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public GirlFriend getGf() {
        return gf;
    }
    public void setGf(GirlFriend gf) {
        this.gf = gf;
    }
    
    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class GirlFriend {
    String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public class TestClone {
    public static void main(String[] args) {
        Boy xiaoming = new Boy();
        xiaoming.setName("小明");
        GirlFriend xiaomei = new GirlFriend();
        xiaomei.setName("小美");
        xiaoming.setGf(xiaomei);
        
        Boy clone = (Boy) xiaoming.clone(); //小明的克隆人
        
        clone.getGf().setName("小丽"); //克隆人的女朋友
        
        System.out.println(xiaoming.getName() + "的女朋友是" + xiaoming.getGf().getName());
        System.out.println(clone.getName() + "的克隆人的女朋友是" + clone.getGf().getName());
    }
}

运行结果:

小明的女朋友是小丽
小明的克隆人的女朋友是小丽

乱了,全乱了。。。
以上,就是浅拷贝。clone对象赋值了小明的String name,因为名字是个基本类型String,但是女朋友gf是个引用类型GirlFriend,经过拷贝之后clone对象只是简单将自己的gf变量指向了同一个GirlFriend对象。
所以当试图给克隆人重新介绍女朋友的时候,clone.getGf().setName("小丽")也修改了原对象小明的女朋友。酿成了杯具。所以,我们需要深拷贝。
修改上面的代码:

public class GirlFriend implements Cloneable{
    String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public Object clone(){
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class Boy implements Cloneable{
    private String name;
    private GirlFriend gf;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public GirlFriend getGf() {
        return gf;
    }
    public void setGf(GirlFriend gf) {
        this.gf = gf;
    }
    
    @Override
    public Object clone() {
        try {
            GirlFriend gf_clone = (GirlFriend) gf.clone();
            Boy clone = (Boy) super.clone();
            clone.setGf(gf_clone); //女朋友也克隆一个
            return clone;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

运行结果

小明的女朋友是小美
小明的克隆人的女朋友是小丽

正确了,大家都美滋滋。

总结

深拷贝和浅拷贝都是要实现Cloneable接口,然后Override重新Object clone()方法。
但是一个对象如果都只是调用父类也就是Object类的clone方法的话只是实现了浅拷贝,如果要实现深拷贝,方法是在clone方法内部除了调用super.clone()之外,对本对象的引用类型的成员再进行clone一次。就像上面的程序里对gf.clone()那样。
深拷贝的实现还有一种方法,就是对对象进行序列化,然后再反序列化回来,就可以得到一个深拷贝之后的全新的对象了。

上一篇 下一篇

猜你喜欢

热点阅读