Clone方法与浅拷贝&深拷贝

本文介绍了Java中Clone方法用于创建对象副本的原理,强调了浅拷贝和深拷贝的区别。在实现Cloneable接口并重写Object.clone()方法时,若对象包含可变成员,浅拷贝可能导致原生对象与克隆对象共享状态。为确保独立,需要进行深拷贝,即递归复制可变对象。数组的clone方法默认执行浅拷贝,处理包含可变对象的数组时需特别注意。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

在Java中,如果需要创建一个对象的副本,特别是这个对象的创建需要很大代价时,可以使用Clone()方法快速高效创建对象副本。

如何实现

实现Cloneable接口,重写Object.clone()方法即可。

class OracleDriver implements Cloneable{

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public OracleDriver clone() throws CloneNotSupportedException {
        return (OracleDriver) super.clone();
    }
}

通常来说,clone之后的对象与原生对象应该是相互独立的,没有任何关联的,为了使原生对象与克隆对象保持独立,需要视不同情况使用浅拷贝与深拷贝。

当类中包含可变对象时,如果使用浅拷贝,就会发生以下情况:

class OtherInfo{
    private String name;

    /* getter & setter*/

    @Override
    public String toString() {
        return "hashCode= {" + hashCode() + "}OtherInfo{" +
                "name='" + name + '\'' +
                '}';
    }
}

class OracleDriver implements Cloneable{

    private String name;
    private OtherInfo otherInfo;

    public OracleDriver(OtherInfo otherInfo){
        this.otherInfo = otherInfo;
    }

	/* getter & setter*/

    @Override
    public OracleDriver clone() throws CloneNotSupportedException {
        return (OracleDriver) super.clone();
    }

    @Override
    public String toString() {
        return "hashCode= {" + hashCode() + "}OracleDriver{" +
                "name='" + name + '\'' +
                ", otherInfo=" + otherInfo +
                '}';
    }
}

	public static void main(String[] args) throws CloneNotSupportedException {
        OracleDriver origin = new OracleDriver(new OtherInfo());
        OracleDriver clone = origin.clone();

        System.out.println("origin:" + origin);
        System.out.println("clone:" + clone);
    }
    
    /*
    打印结果:
    origin:hashCode= {1175962212}OracleDriver{name='null', otherInfo=hashCode= {918221580}OtherInfo{name='null'}}
    clone:hashCode= {2055281021}OracleDriver{name='null', otherInfo=hashCode= {918221580}OtherInfo{name='null'}}
    */

结果

可以看到原生对象与克隆对象引用的OtherInfo的hashCode是一致的,也就是引用的是同一个实例对象,这种情况下,原生对象与克隆对象是存在关联的,当原生对象修改了OtherInfo对象时,克隆对象也被修改了,这样是不行的。这时候需要深拷贝。

浅拷贝 shallow copy

当一个类中的成员变量只包含8中原生数据类型或者是不可变数据类型的变量时,只需要当前类实现Cloneable接口即可。

class OracleDriver implements Cloneable{

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public OracleDriver clone() throws CloneNotSupportedException {
        return (OracleDriver) super.clone();
    }
}

深拷贝 deep copy

当一个类中的成员变量存在可变数据类型的变量时,比如引用了另一个类,为了保持原生对象与克隆对象相互独立,需要在clone()方法返回之前,修改这些可变对象,通常会clone这些可变对象,并使用克隆对象替换这些可变对象。

OracleDriver引用了OtherInfo

class OracleDriver implements Cloneable{

    private String name;
    private OtherInfo otherInfo;

    public OracleDriver(OtherInfo otherInfo){
        this.otherInfo = otherInfo;
    }

    @Override
    public OracleDriver clone() throws CloneNotSupportedException {
        OracleDriver oracleDriver = (OracleDriver) super.clone();
        OtherInfo otherInfo = oracleDriver.getOtherInfo().clone();
        oracleDriver.setOtherInfo(otherInfo);
        return oracleDriver;
    }

    @Override
    public String toString() {
        return "hashCode= {" + hashCode() + "}OracleDriver{" +
                "name='" + name + '\'' +
                ", otherInfo=" + otherInfo +
                '}';
    }

引用类也需要实现Cloneable接口

class OtherInfo implements Cloneable{
    private String name;

    @Override
    protected OtherInfo clone() throws CloneNotSupportedException {
        return (OtherInfo) super.clone();
    }

    @Override
    public String toString() {
        return "hashCode= {" + hashCode() + "}OtherInfo{" +
                "name='" + name + '\'' +
                '}';
    }
}

结果

可以看到原生对象与克隆对象应用的OtherInfo是两个实例,原生对象与克隆对象彼此不影响。

public static void main(String[] args) throws CloneNotSupportedException {
    OracleDriver origin = new OracleDriver(new OtherInfo());
    OracleDriver clone = origin.clone();

    System.out.println("origin:" + origin);
    System.out.println("clone:" + clone);
}
/*
打印结果:
origin:hashCode= {1175962212}OracleDriver{name='null', otherInfo=hashCode= {918221580}OtherInfo{name='null'}}
clone:hashCode= {2055281021}OracleDriver{name='null', otherInfo=hashCode= {1554547125}OtherInfo{name='null'}}
*/

数组中的clone

在Java中,数组对象已经原生实现了Cloneable接口,但实现的是浅拷贝。所以当数组中存在可变对象时,需要自行替换掉这些可变对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cuidianjay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值