笔友城堡 - 可定义的个人主页

前言

简单记录一下Java面试中的克隆,已经对象的深拷贝浅拷贝相关的知识。

记录于此,方便自己查阅和学习。

正文

下面分别介绍一下克隆,深拷贝和浅拷贝相关知识。

克隆

定义:克隆就是创建一个对象的副本

  • Java 提供了Object.clone()方法

  • 要使用克隆,类必须实现 Cloneable接口

  • Cloneable是一个 标记接口(Marker Interface)

  • 未实现Cloneable调用clone()会抛CloneNotSupportedException

浅拷贝

定义:只复制对象本身和基本类型字段,引用类型字段仍然指向原对象

示例

class Address {
    String city;
}

class Person implements Cloneable {
    int age;
    Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 默认浅拷贝
    }
}
Person p1 = new Person();
p1.address = new Address();
p1.address.city = "Beijing";

Person p2 = (Person) p1.clone();
p2.address.city = "Shanghai";

System.out.println(p1.address.city); //输出:Shanghai

原因:address是引用类型,拷贝的是引用地址

p2指向了pi的地址

深拷贝

定义:不仅复制对象本身,还递归复制引用类型字段,新对象与原对象完全独立

实现方式一

重写 clone()

class Address implements Cloneable {
    String city;

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

class Person implements Cloneable {
    int age;
    Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        person.address = (Address) this.address.clone(); // 关键
        return person;
    }
}

修改p2.address不会影响p1。

实现方式二

序列化

// 所有对象实现 Serializable
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(person);

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Person deepCopy = (Person) ois.readObject();

自动深拷贝

缺点:性能差、代码重、不适合复杂对象

实现方式三

手动new

Person copy = new Person();
copy.age = this.age;
copy.address = new Address();
copy.address.city = this.address.city;

优点:可读性好、可控、无反射/序列化风险

浅拷贝VS深拷贝

对比点浅拷贝深拷贝
对象本身新对象新对象
基本类型复制值复制值
引用类型共享引用新建对象
修改引用对象互相影响互不影响
实现难度简单较复杂
性能

小结

浅拷贝复制引用,深拷贝复制对象;Java 默认是浅拷贝,深拷贝需要自己实现。

  1. 克隆是通过Object.clone()创建对象副本的一种方式

  2. Java中默认的clone()是浅拷贝,只会复制对象本身和基本类型字段,引用类型字段仍然指向原对象

  3. 深拷贝会在拷贝对象的同时,递归复制引用对象,使新对象与原对象完全独立

  4. 实现深拷贝可以通过重写 clone()、手动 new 对象,或者通过序列化完成。

为什么需要实现 Cloneable?
  • Cloneable是标记接口

  • JVM用它判断是否允许克隆

  • 否则抛 CloneNotSupportedException

clone()是深拷贝还是浅拷贝?

默认是浅拷贝

为什么很多项目不用 clone()?
  • 实现复杂

  • 易破坏封装

  • 构造器更安全

  • 推荐使用构造函数 / Builder / 拷贝工具

深拷贝一定好吗?

不一定

  • 性能开销大

  • 循环引用问题

  • 实际业务大多只需要“部分拷贝”

参考文章

AI

相关网址

笔友城堡 - 可定义的个人主页

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...