【JAVA基础面经】深拷贝与浅拷贝

文章目录


基本概念

  • 浅拷贝:创建一个新对象,然后将原对象的非静态字段(基本类型和引用类型)直接复制到新对象中。对于引用类型字段,复制的是引用地址,即新对象和原对象中的引用字段指向同一个实例。因此,修改其中一个对象的引用字段内容,会影响另一个对象。

  • 深拷贝:创建一个新对象,并递归地复制原对象中所有引用类型字段所引用的对象,直到所有层次都被完全复制。新对象和原对象完全独立,修改一个不会影响另一个。


浅拷贝

&emap;默认的 super.clone() 执行的是浅拷贝,此时p1 和 p2 的 address 引用指向同一个 Address 对象,因此修改 p2 的地址会影响 p1

java 复制代码
class Address {
    String city;
    Address(String city) { this.city = city; }
    // getter/setter 省略
}

class Person implements Cloneable {
    String name;
    Address address;

    Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 浅拷贝
    }

    // getter/setter 省略
}

public class ShallowCopyDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("北京");
        Person p1 = new Person("张三", addr);
        Person p2 = (Person) p1.clone();

        System.out.println(p1.address.city); // 北京
        System.out.println(p2.address.city); // 北京

        // 修改 p2 的地址
        p2.address.city = "上海";
        System.out.println(p1.address.city); // 上海 → 影响原对象
        System.out.println(p2.address.city); // 上海
    }
}

深拷贝

重写 clone() 方法实现深拷贝

 在 clone() 方法中,不仅要调用 super.clone(),还要对引用类型字段手动进行拷贝(通常也调用其 clone() 方法,要求被引用的类也支持克隆)。

java 复制代码
class Address implements Cloneable {
    String city;
    Address(String city) { this.city = city; }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // Address 内部只有基本类型/不可变,浅拷贝即可
    }
}

class Person implements Cloneable {
    String name;
    Address address;

    Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();   // 浅拷贝基础字段
        cloned.address = (Address) address.clone(); // 深拷贝 address
        return cloned;
    }
}

使用序列化实现深拷贝

 将对象写入流再从流中读出,可以自动实现深拷贝(要求所有引用类型都实现 Serializable 接口)。序列化方式的优点是不需要为每个类手动编写拷贝逻辑,但要求所有涉及类都实现 Serializable,且性能相对较低。

java 复制代码
import java.io.*;

class Address implements Serializable {
    String city;
    Address(String city) { this.city = city; }
}

class Person implements Serializable {
    String name;
    Address address;

    Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    // 深拷贝方法
    public Person deepCopy() {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(this);
            try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bis)) {
                return (Person) ois.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

使用复制构造函数或工厂方法

 手动编写一个构造函数,接收同类型对象并逐一复制字段,对于引用类型也递归复制。这种方式清晰直观,但需要为每个类编写拷贝逻辑,且当对象图复杂时容易遗漏。

java 复制代码
class Address {
    String city;
    Address(String city) { this.city = city; }
    // 复制构造函数
    Address(Address other) {
        this.city = other.city;
    }
}

class Person {
    String name;
    Address address;

    Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    // 复制构造函数(深拷贝)
    Person(Person other) {
        this.name = other.name;
        this.address = new Address(other.address); // 复制 address
    }
}
相关推荐
KJ_BioMed5 小时前
从PDB到高亲和力分子:De novo生成式计算化学Pipeline剖析
算法·生物医药·生物科研·科研干货·化合物设计
一个王同学6 小时前
从零到一 | CV转多模态大模型 | week17 | LLM 推理优化 & vLLM 详解
人工智能·深度学习·算法·机器学习·计算机视觉·vllm
jimy16 小时前
C语言模拟对象、方法:“函数指针+结构体“复用函数指针指向的函数体
c语言·开发语言
程序员张36 小时前
SpringBoot集成BCrypt密码加密库
java·spring boot·后端
闲猫6 小时前
Spring AI Agentic 模式(第1部分):Agent Skills——模块化、可复用的能力
java·人工智能·spring
源图客6 小时前
云途物流API开发-鉴权认证(Java)
java·网络·python
天外天-亮6 小时前
HBuilder X 使用 uview-plus 方式
开发语言·javascript·hbuilder x·uview-plus
liguojun20256 小时前
篮球馆自动计时收费系统:从规则配置到自动结算的全流程拆解
java·大数据·运维·人工智能·物联网·1024程序员节
木木子227 小时前
[特殊字符] 音乐播放器——状态驱动的多媒体控制
android·开发语言·华为·php·harmonyos
旖-旎7 小时前
《LeetCode 53 最大子数组和 || LeetCode 918 环形子数组的最大和》
c++·算法·leetcode·动态规划