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

Java | 深拷贝与浅拷贝工具类解析和自定义实现

关注:CodingTechWork

引言

  在 Java 开发中,对象的拷贝是一个常见的需求,尤其是在处理复杂数据结构时。深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两种常见的拷贝方式,它们在实现和效果上有着显著的区别。本文将详细介绍深拷贝和浅拷贝的概念、区别,并通过 Java 代码示例进行说明。同时,还会介绍一些常用的深拷贝工具类以及如何自己实现一个深拷贝工具。

深拷贝与浅拷贝的概念

浅拷贝

浅拷贝是指创建一个新对象,然后将当前对象的非静态字段复制到新对象中。如果字段是值类型的(如基本数据类型或不可变对象),那么将复制字段的值;如果字段是引用类型的(如数组、集合、自定义对象等),则复制引用但不复制引用的对象。因此,原始对象和副本对象将引用同一个对象。

深拷贝

深拷贝是指创建一个新对象,然后递归地将当前对象的所有字段(包括值类型和引用类型)复制到新对象中。对于引用类型的字段,深拷贝会创建一个新的对象,并将其复制到副本对象中。因此,原始对象和副本对象是完全独立的,修改一个对象不会影响另一个对象。

深拷贝与浅拷贝的区别

特性浅拷贝深拷贝
值类型字段复制字段的值复制字段的值
引用类型字段复制引用,不复制引用的对象创建新的对象,并复制引用的对象
修改影响修改原始对象可能影响副本对象修改原始对象不会影响副本对象
实现复杂度简单复杂,需要递归
性能较快较慢,尤其是对象结构复杂时

浅拷贝与深拷贝的代码示例

浅拷贝示例

import java.util.Arrays;class Person {private String name;private String[] address;public Person(String name, String[] address) {this.name = name;this.address = address;}public String getName() {return name;}public String[] getAddress() {return address;}// 浅拷贝方法public Person shallowCopy() {return new Person(this.name, this.address);}
}public class ShallowCopyDemo {public static void main(String[] args) {// 创建原始对象Person original = new Person("Alice", new String[]{"123 Main St", "Apt 456"});// 浅拷贝Person shallowCopied = original.shallowCopy();// 修改原始对象的地址original.getAddress()[0] = "456 Elm St";System.out.println("Original Address: " + Arrays.toString(original.getAddress()));System.out.println("Shallow Copied Address: " + Arrays.toString(shallowCopied.getAddress()));}
}

输出:

Original Address: [456 Elm St, Apt 456]
Shallow Copied Address: [456 Elm St, Apt 456]

从输出可以看到,修改原始对象的地址也影响了浅拷贝的对象,因为它们共享同一个地址数组。

深拷贝示例

import java.util.Arrays;class Person {private String name;private String[] address;public Person(String name, String[] address) {this.name = name;this.address = address;}public String getName() {return name;}public String[] getAddress() {return address;}// 深拷贝方法public Person deepCopy() {// 创建新的地址数组String[] newAddress = new String[this.address.length];System.arraycopy(this.address, 0, newAddress, 0, this.address.length);return new Person(this.name, newAddress);}
}public class DeepCopyDemo {public static void main(String[] args) {// 创建原始对象Person original = new Person("Alice", new String[]{"123 Main St", "Apt 456"});// 深拷贝Person deepCopied = original.deepCopy();// 修改原始对象的地址original.getAddress()[0] = "456 Elm St";System.out.println("Original Address: " + Arrays.toString(original.getAddress()));System.out.println("Deep Copied Address: " + Arrays.toString(deepCopied.getAddress()));}
}

输出:

Original Address: [456 Elm St, Apt 456]
Deep Copied Address: [123 Main St, Apt 456]

从输出可以看到,修改原始对象的地址不会影响深拷贝的对象,因为深拷贝创建了一个全新的地址数组。

深拷贝的常用工具类

在 Java 中,有一些常用的工具类可以帮助实现深拷贝,例如 SerializationUtilsJSON 序列化。

使用 SerializationUtils 实现深拷贝

SerializationUtils 是 Apache Commons Lang 提供的工具类,可以利用序列化机制实现深拷贝。以下是示例代码:

import org.apache.commons.lang3.SerializationUtils;import java.io.Serializable;class Person implements Serializable {private String name;private String[] address;public Person(String name, String[] address) {this.name = name;this.address = address;}public String getName() {return name;}public String[] getAddress() {return address;}
}public class SerializationUtilsDemo {public static void main(String[] args) {// 创建原始对象Person original = new Person("Alice", new String[]{"123 Main St", "Apt 456"});// 使用 SerializationUtils 实现深拷贝Person deepCopied = SerializationUtils.clone(original);// 修改原始对象的地址original.getAddress()[0] = "456 Elm St";System.out.println("Original Address: " + Arrays.toString(original.getAddress()));System.out.println("Deep Copied Address: " + Arrays.toString(deepCopied.getAddress()));}
}

输出:

Original Address: [456 Elm St, Apt 456]
Deep Copied Address: [123 Main St, Apt 456]

使用 JSON 序列化实现深拷贝

JSON 序列化是一种常见的深拷贝方式,可以利用 GsonJackson 等库实现。以下是使用 Gson 的示例代码:

import com.google.gson.Gson;class Person {private String name;private String[] address;public Person(String name, String[] address) {this.name = name;this.address = address;}public String getName() {return name;}public String[] getAddress() {return address;}
}public class GsonDemo {public static void main(String[] args) {// 创建原始对象Person original = new Person("Alice", new String[]{"123 Main St", "Apt 456"});// 使用 Gson 实现深拷贝Gson gson = new Gson();String json = gson.toJson(original);Person deepCopied = gson.fromJson(json, Person.class);// 修改原始对象的地址original.getAddress()[0] = "456 Elm St";System.out.println("Original Address: " + Arrays.toString(original.getAddress()));System.out.println("Deep Copied Address: " + Arrays.toString(deepCopied.getAddress()));}
}

输出:

Original Address: [456 Elm St, Apt 456]
Deep Copied Address: [123 Main St, Apt 456]

自己实现深拷贝工具类

如果需要更灵活的深拷贝实现,可以自己编写一个工具类。以下是一个简单的深拷贝工具类的实现:

import java.util.ArrayList;
import java.util.List;public class DeepCopyUtils {public static <T> T deepCopy(T object) {if (object == null) {return null;}// 检查是否是基本数据类型或不可变对象if (object instanceof String || object instanceof Number || object instanceof Boolean) {return object;}// 检查是否是数组if (object.getClass().isArray()) {Object[] array = (Object[]) object;Object[] newArray = new Object[array.length];for (int i = 0; i < array.length; i++) {newArray[i] = deepCopy(array[i]);}return (T) newArray;}// 检查是否是集合if (object instanceof List) {List<Object> list = (List<Object>) object;List<Object> newList = new ArrayList<>();for (Object item : list) {newList.add(deepCopy(item));}return (T) newList;}// 如果是自定义对象,需要手动处理if (object instanceof Person) {Person person = (Person) object;return (T) new Person(person.getName(), deepCopy(person.getAddress()));}throw new IllegalArgumentException("Unsupported type: " + object.getClass().getName());}private static String[] deepCopy(String[] array) {if (array == null) {return null;}String[] newArray = new String[array.length];System.arraycopy(array, 0, newArray, 0, array.length);return newArray;}public static void main(String[] args) {// 创建原始对象Person original = new Person("Alice", new String[]{"123 Main St", "Apt 456"});// 使用自定义工具类实现深拷贝Person deepCopied = DeepCopyUtils.deepCopy(original);// 修改原始对象的地址original.getAddress()[0] = "456 Elm St";System.out.println("Original Address: " + Arrays.toString(original.getAddress()));System.out.println("Deep Copied Address: " + Arrays.toString(deepCopied.getAddress()));}
}

输出:

Original Address: [456 Elm St, Apt 456]
Deep Copied Address: [123 Main St, Apt 456]

总结

概念

  • 浅拷贝:只复制对象的直接字段,对于引用类型字段,复制的是引用而不是对象本身。
  • 深拷贝:递归复制对象的所有字段,包括引用类型字段所指向的对象。

区别

  • 浅拷贝创建的对象与原始对象可能共享引用类型字段所指向的对象,而深拷贝创建的对象与原始对象完全独立。
  • 深拷贝的实现更复杂,性能开销更大,但可以保证对象的完全独立性。

实现方式

  • 浅拷贝:可以通过 Object.clone() 方法或手动实现。
  • 深拷贝:可以通过手动递归实现、利用序列化机制(如 SerializationUtils)、JSON 序列化(如 GsonJackson)或自定义工具类实现。

选择建议

  • 如果对象结构简单,且不需要完全独立的副本,可以选择浅拷贝。
  • 如果需要完全独立的副本,尤其是对象结构复杂时,建议使用深拷贝。
  • 在实际开发中,可以根据具体需求选择合适的实现方式,或者结合多种方式实现更灵活的拷贝逻辑。
http://www.xdnf.cn/news/1468.html

相关文章:

  • 今日行情明日机会——20250423
  • 协程gevent案例
  • 从代码学习深度学习 - 自动并行 PyTorch 版
  • AI飞行行为的可解释性与合规审计机制设计
  • React SSR + Redux 导致的 Hydration 报错踩坑记录与修复方案
  • 亚信安全与联通数科达成战略合作,成立联信事业部
  • 深入学习Axios:现代前端HTTP请求利器
  • flex修改主轴方向
  • 深入理解指针(2)
  • git提交
  • ctfhub-RCE
  • CDN加速http请求
  • 腾讯秋招面试题:bug生命周期中有哪些状态?
  • rl中,GRPO损失函数详解。
  • 需求质量验证-测试需求
  • GitLab_密钥生成(SSH-key)
  • 思科路由器密码绕过+重置
  • Vue 3中如何封装API请求:提升开发效率的最佳实践
  • Reactor编程模型介绍
  • Vue3 小功能记录:密码的显示与隐藏功能
  • WebXR教学 05 项目3 太空飞船小游戏
  • Synternet数据流正式上线Google Cloud Web3
  • FreeRTOS深度解析:队列集(Queue Sets)的原理与应用
  • Alertmanager的安装和详细使用步骤总结
  • 【锂电池剩余寿命预测】CNN卷积神经网络锂电池剩余寿命预测(Pytorch完整源码和数据)
  • 大模型RAG的召回模式
  • Vite vs Webpack 优势对比
  • 抱佛脚之学SSM六
  • 4.多表查询
  • AI与智能金融服务:如何利用AI分析大数据预测金融市场波动?