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

Java学习-------序列化与反序列化

        在现代软件开发中,数据的传输与存储是核心环节之一。无论是分布式系统中不同节点间的数据交换,还是应用程序对对象状态的持久化保存,都离不开一种关键技术 —— 序列化与反序列化。它们如同数据的 “转换器”,让内存中的对象能够跨越边界进行传递和留存。

        序列化是指将内存中的对象状态转换为可传输或可存储的二进制流、XML、JSON 等格式的过程。简单来说,就是把对象 “打包装”,变成一种能在网络上传输或者能存入文件的形式。​

        而反序列化则是序列化的逆过程,指将序列化后的数据(如二进制流、XML、JSON 等)重新转换为内存中对象的过程,相当于把 “包裹” 拆开,恢复成原来的对象状态。​

        例如,在远程调用中,客户端需要将请求参数对象序列化后发送给服务器,服务器接收到数据后进行反序列化,得到原始对象并处理;当需要保存程序的运行状态时,也可以将对象序列化后存入磁盘,下次启动时再通过反序列化恢复状态。​

        序列化与反序列化的核心原理是数据格式的转换与重构。在内存中,对象由属性、方法和引用关系等组成,但方法是可执行的代码,无需存储或传输,因此序列化的核心是对对象的属性数据进行处理。​其基本流程如下:​

(1)序列化过程:系统遍历对象的所有可序列化属性,按照一定的规则(如特定的二进制格式、标签结构等)将这些属性的值转换为字节序列或文本格式。在这个过程中,需要处理对象的继承关系、引用关系(避免循环引用导致的无限递归)等复杂情况。​

(2)反序列化过程:系统读取序列化后的数据,根据数据中包含的类型信息和结构信息,重新创建对象实例,并为其属性赋值,同时恢复对象之间的引用关系,最终在内存中还原出与序列化前一致的对象结构。​

        不同的序列化框架(如 Java 原生序列化、JSON 序列化、Protobuf 等)采用的具体格式和规则不同,但核心都是通过 “标记数据类型 + 记录属性值 + 处理关系” 来实现对象的转换与重构。​

        序列化与反序列化是数据交互和持久化的基础,其作用主要体现在以下几个方面:​

(1)数据传输:在分布式系统、微服务架构或客户端 - 服务器模式中,不同进程或节点运行在不同的内存空间,对象无法直接共享。通过序列化将对象转为可传输格式(如网络字节流),能实现跨进程、跨节点的数据交换。​

(2)数据持久化:内存中的对象会随着程序关闭而消失,序列化可以将对象状态保存到磁盘文件、数据库等存储介质中,实现对象状态的长期留存,下次程序启动时通过反序列化恢复。​

(3)对象复制:通过序列化再反序列化的过程,可以创建一个与原对象属性完全相同的新对象,实现对象的深拷贝(避免引用传递导致的修改冲突)。​

(4)跨语言交互:采用 JSON、XML 等通用格式进行序列化时,不同编程语言(如 Java、Python、Go)可以通过解析相同的格式实现对象的交互,打破语言壁垒。​

        序列化与反序列化的优点主要有:

(1)实现数据跨边界流动:解决了内存中对象无法直接在网络传输或持久化存储的问题,是分布式系统、远程通信的基础。​

(2)便于数据持久化管理:通过序列化将对象存入存储介质,能长期保存程序状态,提高数据的可用性和容错性。​

(3)简化数据交互流程:统一的序列化格式(如 JSON)让不同系统、不同语言之间的数据交换更加简单,减少了格式转换的复杂度。​

(4)支持对象状态复制:利用序列化与反序列化实现对象深拷贝,避免了直接引用带来的副作用,便于对象的复用和隔离。​

        但是其也有不少缺点,如:​

(1)性能开销:序列化与反序列化需要进行数据格式转换和结构解析,会消耗一定的 CPU 和内存资源,尤其是对大型对象或高频数据交互场景,可能成为性能瓶颈。​

(2)版本兼容性问题:如果类的结构发生变化(如增减属性、修改属性类型),旧版本的序列化数据可能无法正确反序列化,需要额外处理版本兼容问题。​

(3)安全风险:反序列化过程可能被恶意利用,攻击者通过构造恶意序列化数据,在反序列化时执行恶意代码(如 Java 中的反序列化漏洞),导致系统被入侵。​

(4)数据格式限制:不同的序列化框架支持的数据类型和格式不同,部分框架可能不支持复杂对象(如循环引用对象)的序列化,或序列化后的数据体积过大。​

        下面通过 Java 代码示例演示序列化与反序列化的实现,以 Java 原生的序列化机制为例(基于Serializable接口)。​

import java.io.Serializable;// 可序列化的实体类
// 实现Serializable接口,表示该类可序列化
public class User implements Serializable {// 序列化版本号,用于版本控制private static final long serialVersionUID = 1L;private String name;private int age;// transient修饰的属性不会被序列化private transient String introduce;public User(String name, int age, String password) {this.name = name;this.age = age;this.introduce = introduce;}@Overridepublic String toString() {return "User{name='" + name + "', age=" + age + ", introduce='" + introduce + "'}";}
}
import java.io.*;// 序列化与反序列化工具类
public class SerializationUtils {// 序列化:将对象写入文件public static void serialize(Object obj, String filePath) throws IOException {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {oos.writeObject(obj);}}// 反序列化:从文件读取对象public static Object deserialize(String filePath) throws IOException, ClassNotFoundException {try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath))) {return ois.readObject();}}
}
import java.io.IOException;public class SerializationTest {public static void main(String[] args) {String filePath = "user.ser";User user = new User("浩二", 24, "是个学生");try {// 序列化SerializationUtils.serialize(user, filePath);System.out.println("序列化成功,原始对象:" + user);// 反序列化User deserializedUser = (User) SerializationUtils.deserialize(filePath);System.out.println("反序列化成功,恢复对象:" + deserializedUser);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
序列化成功,原始对象:User{name='浩二', age=24, introduce='是个学生'}
反序列化成功,恢复对象:User{name='浩二', age=24, introduce='null'}

        从结果可以看出,被transient修饰的password属性未被序列化,反序列化后为null,其他属性则成功恢复。这也体现了 Java 原生序列化的特性:仅序列化对象的非 transient 属性,且需要类实现Serializable接口并指定serialVersionUID以保证版本兼容。​

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

相关文章:

  • MGRE综合实验
  • 【Linux | 网络】传输层(UDP和TCP)
  • 笔记本键盘的启用和禁用
  • Rust实战:高效开发技巧
  • 强连通分量:Kosaraju算法
  • 使用Python绘制动态樱花
  • CentOS 镜像源配置与 EOL 后的应对策略
  • 【C++篇】STL的关联容器:unordered_map和unordered_set(上篇):哈希表的模拟实现
  • Triton Shared编译
  • Linux网络-------2.应⽤层⾃定义协议与序列化
  • 大模型算法面试笔记——常用优化器SGD,Momentum,Adagrad,RMSProp,Adam
  • Spring MVC设计精粹:源码级架构解析与实践指南
  • AI Coding IDE 介绍:Cursor 的入门指南
  • 深度学习计算(深度学习-李沐-学习笔记)
  • Python 程序设计讲义(23):循环结构——循环控制语句 break 与 continue
  • 【笔记】Einstein关系式 D = ukBT 的推导与应用研究
  • 【自动化运维神器Ansible】Ansible常用模块之hostname模块详解
  • Java面试实战:企业级性能优化与JVM调优全解析
  • 【编号444】雅鲁藏布江(上中下)游8级水系湖泊数据合集
  • cacti漏洞CVE-2022-46169的复现
  • Java:采用mybatis+pagehealper优雅的实现分页功能
  • 如何筛选适合自己阅读的文献?高效文献调研流程?
  • 【C++高效编程】STL queue深度剖析:从底层原理到高级应用
  • FastAPI入门:安装、Pydantic、并发和并行
  • 嵌入式硬件篇---有线串口通信问题解决
  • 使用Clion开发STM32(Dap调试)
  • Android WorkManager 详解:高效管理后台任务
  • hot100-每日温度
  • Python爬虫实战:诗词名句网《三国演义》全集
  • obd运维OceanBase数据库的常见场景