吃透Java基础七:浅拷贝与深拷贝

一:什么是浅拷贝和深拷贝

  • 浅拷贝:原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。也就是说:在浅拷贝中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
  • 深拷贝:无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。也就是说:在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

实现对象克隆有两种方式:

  • 实现Cloneable接口并重写Object类中的clone()方法。
  • 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

二:浅拷贝

浅拷贝只需要实现Cloneable,在需要克隆的地方调用clone方法即可,实现起来比较简单。

public class Inner implements Cloneable {
   
}
public class Outer implements Cloneable {
    private Inner inner;

    public Outer(Inner inner) {
        this.inner = inner;
    }

    public Inner getInner() {
        return inner;
    }
}
public class MyTest {

    public static void main(String[] args) {
        Inner inner = new Inner();
        Outer outer = new Outer(inner);
        try {
            Outer cloneOuter = (Outer) outer.clone();
            System.out.println("Outer:" + outer + " cloneOuter:" + cloneOuter);
            System.out.println("Inner:" + outer.getInner() + " cloneInner:" + cloneOuter.getInner());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

输出:

Outer:Outer@4554617c cloneOuter:Outer@74a14482
Inner:Inner@1540e19d cloneInner:Inner@1540e19d

从输出结果可以看出,浅拷贝只是对当前对象Outer创建了一个新的对象,里面的引用类型Inner还是原对象的地址,并没有重新创建一个对象。

三:深拷贝

在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式来实现。

深拷贝实现方式一:通过覆盖Object的clone方法实现

此种方法通过重写Object中的clone方法,并在其内部又对引用类型拷贝来实现的深拷贝,如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。

public class Inner implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Outer implements Cloneable {
    private Inner inner;

    public Outer(Inner inner) {
        this.inner = inner;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Outer outer = (Outer) super.clone();
        outer.inner = (Inner) outer.inner.clone();
        return outer;
    }

    public Inner getInner() {
        return inner;
    }
}
public class MyTest {

    public static void main(String[] args) {
        Inner inner = new Inner();
        Outer outer = new Outer(inner);
        try {
            Outer cloneOuter = (Outer) outer.clone();
            System.out.println("Outer:" + outer + " cloneOuter:" + cloneOuter);
            System.out.println("Inner:" + outer.getInner() + " cloneInner:" + cloneOuter.getInner());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

运行输出:

Outer:Outer@4554617c cloneOuter:Outer@74a14482
Inner:Inner@1540e19d cloneInner:Inner@677327b6

深拷贝实现方式二:通过序列化方式实现

如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。

public class Inner implements Serializable {

}

public class Outer implements Serializable {
    private Inner inner;

    public Outer(Inner inner) {
        this.inner = inner;
    }

    public Inner getInner() {
        return inner;
    }
}
public class MyTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Inner inner = new Inner();
        Outer outer = new Outer(inner);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(outer);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Outer streamOuter = (Outer) objectInputStream.readObject();
        System.out.println("Outer:" + outer + " streamOuter:" + streamOuter);
        System.out.println("Inner:" + outer.getInner() + " streamInner:" + streamOuter.getInner());

    }
}

运行输出:

Outer:Outer@6d6f6e28 streamOuter:Outer@4b67cf4d
Inner:Inner@135fbaa4 streamInner:Inner@7ea987ac
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吃透Java

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值