深入浅出:序列化与反序列化的全面解析
文章目录
- 1. 引言
- 2. 什么是序列化?
- 2.1 为什么需要序列化?
- 3. 什么是反序列化?
- 3.1 反序列化的重要性
- 4. 序列化与反序列化的实现
- 4.1 JSON (JavaScript Object Notation)
- 4.2 XML (eXtensible Markup Language)
- 4.3 Protocol Buffers (Protobuf)
- 4.4 MessagePack
- 5. 安全性考虑
- 6. 性能优化
- 7. 结论
- 附录:常见问题解答
- Q1: 什么时候应该选择JSON而不是XML?
- Q2: Protocol Buffers和MessagePack有什么区别?
- Q3: 如何防止反序列化攻击?
1. 引言
在软件开发中,序列化(Serialization) 和 反序列化(Deserialization) 是两个非常重要的概念。它们涉及到数据的转换、传输和存储。本文将通过通俗易懂的语言和实际代码示例,帮助读者理解这两个过程,并探讨如何在不同的编程语言和应用场景中实现它们。
2. 什么是序列化?
序列化是指将对象的状态信息转换为可以存储或传输的格式的过程。这个格式可以是字节流、JSON、XML等。通过序列化,我们可以将复杂的数据结构简化为一种线性的、易于处理的形式。
2.1 为什么需要序列化?
- 数据传输:当应用程序需要通过网络发送对象时,必须先将其序列化为一种可以在网络上传输的格式。
- 数据存储:为了保存对象状态到文件或数据库,我们需要将对象序列化。
- 缓存:有时我们会将对象序列化后存储在内存或磁盘中作为缓存,以提高访问速度。
- 版本控制:序列化后的数据可以更容易地进行版本管理,尤其是在分布式系统中。
3. 什么是反序列化?
反序列化是序列化的逆过程,即将序列化的数据还原为原始的对象。通过反序列化,我们可以从存储介质或网络接收的数据中重建对象。
3.1 反序列化的重要性
- 数据恢复:从持久存储中读取对象并恢复其状态。
- 网络接收:接收来自网络的序列化数据,并将其转换回可用的对象。
- 跨平台兼容性:不同平台上的程序可以通过序列化和反序列化来共享对象。
4. 序列化与反序列化的实现
不同的编程语言提供了多种方式来实现序列化和反序列化。以下是一些常见的方法及其Java代码示例。
4.1 JSON (JavaScript Object Notation)
JSON是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。许多语言都有内置的库支持JSON序列化和反序列化。在Java中,常用的库有Jackson和Gson。
使用Jackson库
首先,添加Maven依赖:
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.0</version>
</dependency>
然后,编写代码:
import com.fasterxml.jackson.databind.ObjectMapper;import java.io.IOException;public class JsonExample {public static void main(String[] args) throws IOException {// 定义一个Java对象Person person = new Person("Alice", 30, "Beijing");// 创建ObjectMapper实例ObjectMapper objectMapper = new ObjectMapper();// 序列化为JSON字符串String json = objectMapper.writeValueAsString(person);System.out.println("Serialized JSON: " + json);// 反序列化为Java对象Person deserializedPerson = objectMapper.readValue(json, Person.class);System.out.println("Deserialized JSON: " + deserializedPerson);}// 定义Person类static class Person {private String name;private int age;private String city;public Person() {}public Person(String name, int age, String city) {this.name = name;this.age = age;this.city = city;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + ", city='" + city + "'}";}}
}
4.2 XML (eXtensible Markup Language)
XML是一种更复杂的标记语言,适用于描述具有层次结构的数据。尽管它比JSON更冗长,但在某些领域(如配置文件)仍然广泛使用。在Java中,可以使用JAXB(Java Architecture for XML Binding)来进行XML的序列化和反序列化。
使用JAXB库
首先,添加Maven依赖:
<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version>
</dependency>
<dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.1</version>
</dependency>
然后,编写代码:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;public class XmlExample {public static void main(String[] args) throws JAXBException {// 定义一个Java对象Person person = new Person("Alice", 30, "Beijing");// 创建JAXBContext实例JAXBContext context = JAXBContext.newInstance(Person.class);// 序列化为XML字符串Marshaller marshaller = context.createMarshaller();marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);StringWriter writer = new StringWriter();marshaller.marshal(person, writer);String xml = writer.toString();System.out.println("Serialized XML:\n" + xml);// 反序列化为Java对象Unmarshaller unmarshaller = context.createUnmarshaller();StringReader reader = new StringReader(xml);Person deserializedPerson = (Person) unmarshaller.unmarshal(reader);System.out.println("Deserialized XML: " + deserializedPerson);}// 定义Person类,并添加JAXB注解import javax.xml.bind.annotation.XmlRootElement;@XmlRootElementstatic class Person {private String name;private int age;private String city;public Person() {}public Person(String name, int age, String city) {this.name = name;this.age = age;this.city = city;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + ", city='" + city + "'}";}// Getters and Setters (omitted for brevity)}
}
4.3 Protocol Buffers (Protobuf)
Protocol Buffers是由Google开发的一种语言中立、平台中立、可扩展的序列化数据格式。它通常用于网络通信和数据存储。
首先,定义一个.proto文件:
syntax = "proto3";message Person {string name = 1;int32 age = 2;string city = 3;
}
然后,使用protoc编译器生成Java代码:
protoc --java_out=. person.proto
最后,在Java中使用生成的代码进行序列化和反序列化:
import com.example.Person;import java.nio.file.Files;
import java.nio.file.Paths;public class ProtobufExample {public static void main(String[] args) throws Exception {// 创建一个Person对象Person person = Person.newBuilder().setName("Alice").setAge(30).setCity("Beijing").build();// 序列化为字节流byte[] serializedData = person.toByteArray();System.out.println("Serialized Protobuf: " + new String(serializedData));// 反序列化为Person对象Person deserializedPerson = Person.parseFrom(serializedData);System.out.println("Deserialized Protobuf: " + deserializedPerson);}
}
4.4 MessagePack
MessagePack是一种高效的二进制序列化格式,旨在提供紧凑的编码和快速的处理速度。它类似于JSON,但体积更小,性能更高。在Java中,可以使用Kryo库来进行MessagePack的序列化和反序列化。
使用Kryo库
首先,添加Maven依赖:
<dependency><groupId>com.esotericsoftware</groupId><artifactId>kryo</artifactId><version>5.0.0</version>
</dependency>
然后,编写代码:
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;public class MessagePackExample {public static void main(String[] args) {// 定义一个Java对象Person person = new Person("Alice", 30, "Beijing");// 创建Kryo实例Kryo kryo = new Kryo();kryo.register(Person.class);// 序列化为字节流ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();Output output = new Output(byteArrayOutputStream);kryo.writeClassAndObject(output, person);output.close();byte[] packedData = byteArrayOutputStream.toByteArray();System.out.println("Serialized MessagePack: " + Arrays.toString(packedData));// 反序列化为Java对象ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(packedData);Input input = new Input(byteArrayInputStream);Person unpackedPerson = (Person) kryo.readClassAndObject(input);input.close();System.out.println("Deserialized MessagePack: " + unpackedPerson);}// 定义Person类static class Person {private String name;private int age;private String city;public Person() {}public Person(String name, int age, String city) {this.name = name;this.age = age;this.city = city;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + ", city='" + city + "'}";}}
}
5. 安全性考虑
在进行反序列化时,我们必须特别注意安全性问题。恶意用户可能会构造特制的序列化数据,导致程序执行任意代码或造成其他安全漏洞。因此,在反序列化过程中,应该:
- 验证数据来源:确保只对可信来源的数据进行反序列化。
- 限制反序列化的内容:避免反序列化不受信任的类或类型。
- 使用安全的序列化格式:例如,JSON通常被认为比XML更安全,因为它不支持外部实体引用。
6. 性能优化
对于大规模的数据集或高并发的应用场景,序列化和反序列化的性能至关重要。为了提高效率,可以采取以下措施:
- 选择合适的序列化格式:根据应用场景选择最合适的格式,如JSON、MessagePack或Protocol Buffers。
- 批量处理:尽量减少序列化和反序列化的次数,采用批量处理的方式。
- 压缩数据:在传输或存储之前对序列化数据进行压缩,以减少带宽占用和存储空间。
7. 结论
序列化和反序列化是构建高效、可靠的软件系统不可或缺的技术。通过理解它们的工作原理和最佳实践,我们可以更好地应对数据交换和持久化的挑战。无论你是新手还是经验丰富的开发者,掌握这些技能都将为你带来巨大的优势。
附录:常见问题解答
Q1: 什么时候应该选择JSON而不是XML?
A1: JSON通常更适合简单的数据结构和轻量级的应用场景,因为它更简洁、易于阅读和解析。而XML则更适合复杂的、层次结构明显的数据,或者需要严格的模式验证的场景。
Q2: Protocol Buffers和MessagePack有什么区别?
A2: Protocol Buffers由Google开发,支持强类型和严格的消息定义,适合大型项目和跨平台通信。MessagePack则更加灵活,体积更小,性能更高,适合对性能要求较高的场景。
Q3: 如何防止反序列化攻击?
A3: 为了防止反序列化攻击,建议使用安全的序列化格式(如JSON),并严格限制反序列化的内容。此外,还可以通过白名单机制,只允许特定的类或类型进行反序列化。
希望这篇文档能够帮助你了解序列化和反序列化。如果有任何问题,请随时提问!欢迎在评论区交流讨论
相关文章:
深入浅出:序列化与反序列化的全面解析
文章目录 1. 引言2. 什么是序列化?2.1 为什么需要序列化? 3. 什么是反序列化?3.1 反序列化的重要性 4. 序列化与反序列化的实现4.1 JSON (JavaScript Object Notation)4.2 XML (eXtensible Markup Language)4.3 Protocol Buffers (Protobuf)4…...
word实践:正文/标题/表图等的共用模板样式设置
说在前面 最近使用word新建文件很多,发现要给大毛病,每次新建一个word文件,标题/正文的字体、大小和间距都要重新设置一遍,而且每次设置这些样式都忘记了参数,今天记录一下,以便后续方便查看使用。现在就以…...
Blender中使用BlenderGIS插件快速生成城市建筑模型
导入下载 BlenderGIS 插件 去github上下载其压缩包,地址如下: https://github.com/domlysz/BlenderGIS 在BlenderGIS中导入这个插件压缩包: 点击上方菜单栏的编辑,点击偏好设置 在插件>从磁盘安装中导入刚刚下载的压缩包 可…...
【单元测试】单元测试的重要性
1一些错误的认识 在实际的单元测试过程中总会有一些错误的认识左右着我们,使之成为单元测试最大的障碍,在此将其一一分析如下: 它太浪费时间了,现在要赶进度,时间上根本不允许,或者随便做做应付领导。 …...
Codeforces Round 992 (Div. 2)
这场cf只在b卡了一下,因为b真是犯蠢了,我以为会向下取整,结果是完全就不取整,或者说是向上取整,卡了我半个小时,要不是紧急看了题一下,昨天那场就毁了 话不多说,直接开讲 A. Game …...
el-table一键选择全部行,切换分页后无法勾选
el-table一键全选,分页的完美支持 问题背景尝试解决存在问题问题分析 解决方案改进思路如下具体代码实现如下 问题背景 现在有个需求,一个表格有若干条数据(假设数量大于20,每页10条,保证有2个以上分页即可)。 现在需要在表格上方…...
负载均衡最佳实践及自定义负载均衡器
文章目录 负载均衡最佳实践及自定义负载均衡器一、负载均衡概述二、轮询负载均衡器(一)理论介绍(二)Java 实现示例(三)关键步骤(四)流程图 三、随机负载均衡器(一&#x…...
大模型 LMDeploy 量化部署
1 模型部署 定义: 在软件工程中,部署通常指的是将开发完毕的软件投入使用的过程。在人工智能领域,模型部署是实现深度学习算法落地应用的关键步骤。简单来说,模型部署就是将训练好的深度学习模型在特定环境中运行的过程。 场景…...
算法设计5_分支限界法
分支限界法 分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树,裁剪那些不能得到最优解的子树以提高搜索效率。 步骤: ① 定义解空间(对解编码); ② 确定解空间的树结构; ③ 按BFS等方式搜索: a.每个活…...
2025年人工智能专业可以考哪些证书呢?
人工智能是目前全球热门的专业领域之一,随着人工智能应用范围的不断扩大,越来越多的人开始关注人工智能相关证书的获取。那么,人工智能专业可以考什么证书呢?本文将为大家介绍人工智能相关证书的种类。 人工智能机器视觉应用工程师…...
仿真技术助力高尔夫球打破传统设计局限,实现球杆强大的功能
Altair近日宣布与业内领先的高尔夫装备制造商 Cleveland Golf 开展合作,以设计新款 HiBore XL 球杆。借助 Altair 先进的仿真与设计技术,Cleveland Golf 不断刷新高尔夫装备的行业标准,并在球杆产品设计方面实现突破。 Cleveland Golf 借助 A…...
微前端架构学习笔记
前言 之前遇到过一个需求,有两个项目分别由两个不同的部门负责,不同技术栈,不同代码仓库: A 项目是官网,负责展示产品亮点等信息,有多个入口可以进入 B 项目中的不同页面。B 项目是业务线,负责…...
DApp开发:从合约到系统快速上线解决方案
在区块链技术迅猛发展的今天,去中心化应用(DApp)作为区块链的一项重要应用,已经吸引了众多开发者和企业的关注。与传统应用程序不同,DApp依托于区块链的去中心化特点,实现了透明、安全、不可篡改等优势&…...
react 中 useState 中的 set 方法异步解决
使用 useEffect 监听状态的改变。 一、异步特性 在批量处理状态更新时,用以提高性能。 二、异步解决 使用useEffect来处理更新后的状态,useEffect钩子在组件渲染后执行,并且会在依赖项(第二个参数)发生变化时重新执…...
UAC2.0 speaker——带反馈端点的 USB speaker(16bit 单声道)
UAC2.0 speaker 系列文章 UAC2.0 speaker——单声道 USB speaker(16bit) UAC2.0 speaker——类特殊请求 UAC2.0 speaker——音量控制 UAC2.0 speaker——多采样率支持 UAC2.0 speaker——24/32bit 支持 UAC2.0 speaker——speaker 数据传输 UAC2.0 speaker——同时支持 16bi…...
docker的简单使用
文章目录 docker简介docker架构镜像和容器镜像有关的常用命令容器相关常用命令 docker简介 Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。 Docker可以让开方子打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到…...
Selenium:强大的 Web 自动化测试工具
Selenium:强大的 Web 自动化测试工具 在当今的软件开发和测试领域,自动化工具的重要性日益凸显。Selenium 就是一款备受欢迎的 Web 自动化测试工具,它为开发者和测试人员提供了强大的功能和便利。本文将详细介绍 Selenium 是什么,…...
设计模式 在PLM系统的应用场景介绍
通义灵码 设计模式在 PLM(产品生命周期管理)系统中扮演着重要的角色,可以帮助开发人员更好地组织代码、提高系统的可维护性和扩展性。以下是一些常见的设计模式及其在 PLM 系统中的应用场景: 1. 单例模式(Singleton …...
C#请求https提示未能为 SSL/TLS 安全通道建立信任关系
System.Net.WebException: 基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系 ,这个错误通常表明你的应用程序在尝试建立一个安全的 SSL/TLS 连接时遇到了问题。这通常是由于证书验证失败引起的。证书验证失败可能有几个原因: 证书不受信任&#…...
【人工智能】GaussDB数据库技术及应用
文章目录 前言一、数据库的基本概念及发展演进1、数据库概念DB2、数据库管理系统概念DBMS3、数据库与数据库管理系统的关系4、数据库的演进及发展5、数据模型的基本概念6、数据模型的要求和类型7、层次模型的基本概念8、网状模型的基本概念8、关系模型的基本概念9、非关系模型的…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
