当前位置: 首页 > news >正文

Java中的深拷贝与浅拷贝

什么是拷贝

在Java中,拷贝是指创建一个对象的副本。拷贝主要分为两种类型:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。理解这两种拷贝的区别对于编写正确的Java程序非常重要,特别是在处理对象引用时。

浅拷贝(Shallow Copy)

浅拷贝是指创建一个新对象,然后将原始对象的所有字段值复制到新对象中。如果字段是基本类型,则直接复制其值;如果字段是引用类型,则复制引用但不复制引用的对象。因此,原始对象和副本对象将共享引用类型的字段。

浅拷贝的实现方式

在Java中,实现浅拷贝有几种方式:

  1. 使用clone()方法:Object类提供了clone()方法,可以实现浅拷贝

  2. 使用构造方法:通过构造方法复制每个字段

  3. 使用拷贝工厂方法

class Department implements Cloneable {private String name;public Department(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Employee implements Cloneable {private String name;private Department department;public Employee(String name, Department department) {this.name = name;this.department = department;}public String getName() {return name;}public Department getDepartment() {return department;}public void setName(String name) {this.name = name;}public void setDepartment(Department department) {this.department = department;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class ShallowCopyExample {public static void main(String[] args) throws CloneNotSupportedException {Department department = new Department("IT");Employee original = new Employee("John", department);Employee cloned = (Employee) original.clone();System.out.println("Original: " + original.getName() + " - " + original.getDepartment().getName());System.out.println("Cloned: " + cloned.getName() + " - " + cloned.getDepartment().getName());// 修改克隆对象的departmentcloned.getDepartment().setName("HR");System.out.println("\nAfter modifying cloned object:");System.out.println("Original: " + original.getName() + " - " + original.getDepartment().getName());System.out.println("Cloned: " + cloned.getName() + " - " + cloned.getDepartment().getName());}
}

 输出结果:

Original: John - IT
Cloned: John - IT

After modifying cloned object:
Original: John - HR
Cloned: John - HR

可以看到,修改克隆对象的department后,原始对象的department也被修改了,这是因为它们引用的是同一个Department对象。

深拷贝(Deep Copy)

深拷贝是指创建一个新对象,然后递归地复制原始对象的所有字段。对于引用类型的字段,不仅复制引用,还会创建引用对象的新副本。因此,原始对象和副本对象完全独立,互不影响。

深拷贝的实现方式

实现深拷贝有几种常见方法:

  1. 重写clone()方法:在clone()方法中手动复制所有引用类型的字段

  2. 使用序列化:将对象序列化为字节流,然后再反序列化为新对象

  3. 使用拷贝构造方法:创建接受原对象并复制所有字段的构造方法

  4. 使用第三方库:如Apache Commons Lang的SerializationUtils

方法1:重写clone()方法
class Department implements Cloneable {private String name;public Department(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Employee implements Cloneable {private String name;private Department department;public Employee(String name, Department department) {this.name = name;this.department = department;}public String getName() {return name;}public Department getDepartment() {return department;}public void setName(String name) {this.name = name;}public void setDepartment(Department department) {this.department = department;}@Overrideprotected Object clone() throws CloneNotSupportedException {Employee cloned = (Employee) super.clone();cloned.department = (Department) department.clone(); // 深度拷贝departmentreturn cloned;}
}public class DeepCopyExample1 {public static void main(String[] args) throws CloneNotSupportedException {Department department = new Department("IT");Employee original = new Employee("John", department);Employee cloned = (Employee) original.clone();System.out.println("Original: " + original.getName() + " - " + original.getDepartment().getName());System.out.println("Cloned: " + cloned.getName() + " - " + cloned.getDepartment().getName());// 修改克隆对象的departmentcloned.getDepartment().setName("HR");System.out.println("\nAfter modifying cloned object:");System.out.println("Original: " + original.getName() + " - " + original.getDepartment().getName());System.out.println("Cloned: " + cloned.getName() + " - " + cloned.getDepartment().getName());}
}

 输出结果:

Original: John - IT
Cloned: John - IT

After modifying cloned object:
Original: John - IT
Cloned: John - HR

 方法2:使用序列化实现深拷贝

import java.io.*;class Department implements Serializable {private String name;public Department(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}class Employee implements Serializable {private String name;private Department department;public Employee(String name, Department department) {this.name = name;this.department = department;}public String getName() {return name;}public Department getDepartment() {return department;}public void setName(String name) {this.name = name;}public void setDepartment(Department department) {this.department = department;}public Employee deepCopy() throws IOException, ClassNotFoundException {// 将对象写入字节数组ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);oos.flush();// 从字节数组读取对象ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (Employee) ois.readObject();}
}public class DeepCopyExample2 {public static void main(String[] args) throws IOException, ClassNotFoundException {Department department = new Department("IT");Employee original = new Employee("John", department);Employee cloned = original.deepCopy();System.out.println("Original: " + original.getName() + " - " + original.getDepartment().getName());System.out.println("Cloned: " + cloned.getName() + " - " + cloned.getDepartment().getName());// 修改克隆对象的departmentcloned.getDepartment().setName("HR");System.out.println("\nAfter modifying cloned object:");System.out.println("Original: " + original.getName() + " - " + original.getDepartment().getName());System.out.println("Cloned: " + cloned.getName() + " - " + cloned.getDepartment().getName());}
}

 输出结果与上一个相同:

Original: John - IT
Cloned: John - IT

After modifying cloned object:
Original: John - IT
Cloned: John - HR

浅拷贝与深拷贝的比较

特性浅拷贝深拷贝
基本类型字段复制值复制值
引用类型字段复制引用(共享对象)递归复制对象(不共享对象)
实现复杂度简单(通常只需调用super.clone)复杂(需要处理所有引用类型字段)
性能较高(复制较少)较低(需要复制更多对象)
对象独立性低(引用类型字段会相互影响)高(完全独立)

如何选择拷贝方式

选择浅拷贝还是深拷贝取决于具体需求:

  1. 使用浅拷贝的情况

    • 对象的所有字段都是基本类型

    • 引用类型字段是不可变的(如String)

    • 你确实需要共享某些对象的状态

  2. 使用深拷贝的情况

    • 对象包含可变引用类型字段

    • 你需要完全独立的副本

    • 副本的修改不应影响原始对象

注意事项

  1. clone()方法的限制

    • 需要实现Cloneable接口,否则会抛出CloneNotSupportedException

    • clone()方法是protected的,如果要在其他包中调用,需要重写为public

    • 深拷贝实现需要确保所有相关类都正确实现了clone()

  2. 序列化的限制

    • 所有相关类都必须实现Serializable接口

    • 序列化性能较低,不适合频繁拷贝的场景

    • 某些特殊对象(如线程)无法通过序列化正确拷贝

  3. 循环引用问题

    • 在深拷贝时,如果对象图中有循环引用,需要特别处理,否则可能导致栈溢出

最佳实践

1.考虑使用拷贝构造方法拷贝工厂方法替代clone():

public Employee(Employee other) {this.name = other.name;this.department = new Department(other.department);
}

2.对于复杂的对象图,考虑使用第三方库如Apache Commons Lang的SerializationUtils.clone():

Employee cloned = SerializationUtils.clone(original);

3.明确文档化你的拷贝行为,让使用者知道是浅拷贝还是深拷贝。

http://www.xdnf.cn/news/461845.html

相关文章:

  • Blender 入门教程(三):骨骼绑定
  • 三目云台20倍变焦智能监控技术
  • 基于Arduino的迷你掌上游戏机
  • TCP(传输控制协议)建立连接的过程
  • 黑马k8s(七)
  • 用户安全架构设计
  • Unity碰撞检测:射线与胶囊体投射/Layer(层)、LayerMask(遮罩层)
  • 分布式AI推理的成功之道
  • How to configure Linux mint desktop
  • SpringBoot核心优势与适用场景分析
  • 【SPIN】PROMELA语言编程入门基础语法(SPIN学习系列--1)
  • FramePack - 开源 AI 视频生成工具
  • 基于Vue3制作一个可以拖拽排列的卡片,支持nuxt3
  • LeRobot 框架的核心架构概念和组件(下)
  • JAVA:ResponseBodyEmitter 实现异步流式推送的技术指南
  • 兼顾长、短视频任务的无人机具身理解!AirVista-II:面向动态场景语义理解的无人机具身智能体系统
  • 大数据架构选型全景指南:核心架构对比与实战案例 解析
  • 交叉编译JsonCpp
  • go-zero(十八)结合Elasticsearch实现高效数据检索
  • Open CASCADE学习|容器及其使用
  • 2023CCPC河南省赛暨河南邀请赛个人补题ABEFGHK
  • C++篇——多态
  • Uniapp中小程序调用腾讯地图(获取定位地址)
  • C.纸上文字
  • 普通IT的股票交易成长史--20250515复盘
  • 深入解读114页数据资产化治理一体机解决方案:数据资产化技术、治理与未来趋势【付费全文阅读】
  • 还有哪些领域可以应用北斗卫星通讯?
  • AI 编程革命:腾讯云 CodeBuddy 如何重塑开发效率?
  • Profinet转Ethernet/IP网关模块通信协议适配配置
  • 2025认证杯数学建模第二阶段C题:化工厂生产流程的预测和控制,思路+模型+代码