深入浅出:序列化与反序列化的全面解析

文章目录

        • 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),并严格限制反序列化的内容。此外,还可以通过白名单机制,只允许特定的类或类型进行反序列化。


希望这篇文档能够帮助你了解序列化和反序列化。如果有任何问题,请随时提问!欢迎在评论区交流讨论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows命令行使用技巧(持续更新)

删除指定目录下指定后缀的文件 重要的事情说在前面&#xff1a;不能恢复&#xff0c;谨慎操作 今天大意了&#xff0c;导出sql文件的时候没指定目录&#xff0c;默认放到桌面上了&#xff0c;看着桌面上密密麻麻的sql文件&#xff0c;我人傻了&#xff0c;一个一个删不是办法…

LDR6500:音频双C支持,数字与模拟的完美结合

在当今数字化快速发展的时代&#xff0c;音频设备的兼容性和性能成为了用户关注的重点。LDR6500&#xff0c;作为乐得瑞科技精心研发的USB Power Delivery&#xff08;PD&#xff09;协议芯片&#xff0c;凭借其卓越的性能和广泛的应用兼容性&#xff0c;为音频设备领域带来了新…

python rstrip 的迷惑行为

在项目中&#xff0c;我需要把字符串末尾的一部分去掉&#xff0c;类似截断&#xff0c;我用ide的随笔提示&#xff0c;发现了rstrip这个方法&#xff0c;然后我试了下&#xff0c;满足我的需求&#xff0c;但在测试过程中&#xff0c;我发现了rstrip的一些行为很让我迷惑。 开…

计算机网络编程(Linux):I/O多路转接之 select,poll

I/O多路复用&#xff08;I/O Multiplexing&#xff09;是一种高效的网络编程技术&#xff0c;允许一个线程同时监控多个文件描述符的状态&#xff0c;当某个文件描述符就绪时进行相应处理。这种技术在高并发服务器中广泛使用。本文将介绍I/O多路复用的核心概念及在Linux中的实现…

【原生js案例】webApp实现鼠标移入移出相册放大缩小动画

图片相册这种动画效果也很常见&#xff0c;在我们的网站上。鼠标滑入放大图片&#xff0c;滑出就恢复原来的大小。现在我们使用运动定时器来实现这种滑动效果。 感兴趣的可以关注下我的系列课程【webApp之h5端实战】&#xff0c;里面有大量的css3动画效果制作原生知识分析&…

Spring Boot助力,一键解锁招聘全流程信息精细化管理

2系统相关技术 2.1 Java语言介绍 Java是由SUN公司推出&#xff0c;该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称&#xff0c;也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备了显著的优势和广阔的前景&#…

深入理解 NumPy 广播机制:从基础到应用

目录 什么是广播机制&#xff1f;广播机制的规则广播机制示例1. 一维数组与标量运算2. 二维数组与一维数组运算3. 维度不同的数组运算4. 广播失败的情况 广播机制的实际应用场景1. 数据归一化2. 批量计算欧氏距离 总结广播机制的核心要点&#xff1a; 在使用 NumPy 进行数组操作…

Day28两个数组的交集

给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 class Solution{public int[] intersection(int[] nums1, int[] nums2) {Set<Integer> set new HashSet<>();for (int i :…

VRRP的知识点总结及实验

1、VRRP VRRP(Virtual Router Redundancy Protocol&#xff0c;虚拟路由器冗余协议)既能够实现网关的备份&#xff0c;又能解决多个网关之间互相冲突的问题&#xff0c;从而提高网络可靠性。 2、VRRP技术概述&#xff1a; 通过把几台路由设备联合组成一台虚拟的“路由设备”…

DP协议:概括

来了来了&#xff01;&#xff01;&#xff01; 开始之前扯点概念&#xff0c;知道DP好在哪里&#xff0c;以及看到它的发展趋势&#xff0c;才知道我们为什么有学习的必要。 DP的优势 DisplayPort&#xff08;DP&#xff09;协议作为一种专为数字音频和视频传输设计的高速串行…

Ant Design Vue 中 Tree 组件复选框修改样式

一、问题 最近需要实现一个业务需求&#xff0c;要修改勾选框中的颜色&#xff0c;默认勾选框的颜色是蓝色&#xff0c;现在需要变成绿色。 1、官网示例&#xff1a; 2、业务需求&#xff1a; 3、具体实现&#xff1a; HTML 部分代码 <template><div class"s…

【JavaWeb后端学习笔记】登录校验(JWT令牌技术、Interceptor拦截器、Filter过滤器)

登录校验 1、JWT令牌技术1.1 JWT令牌介绍1.2 Java代码生成与校验JWT令牌 2、Filter过滤器2.1 Filter过滤器的简单实现2.2 配置拦截路径2.3 Filter接口中的三个方法&#xff1a;2.4 Filter过滤器登录校验2.5 过滤器链 3、Interceptor拦截器3.1 拦截器(Interceptor)的简单实现3.2…

SpringBoot的Bean类三种注入方式(附带LomBok注入)

SpringBoot的Bean类三种注入方式&#xff08;附带LomBok注入&#xff09; 在 Spring Boot 中&#xff0c;Bean 的注入方式主要包括构造函数注入&#xff08;Constructor Injection&#xff09;、字段注入&#xff08;Field Injection&#xff09;以及 Setter 方法注入&#xf…

Linux系统下常用资源查看

一、查看CPU使用率 top 命令 top命令可以看到总体的系统运行状态和cpu的使用率 。 %us&#xff1a;表示用户空间程序的cpu使用率&#xff08;没有通过nice调度&#xff09; %sy&#xff1a;表示系统空间的cpu使用率&#xff0c;主要是内核程序。 %ni&#xff1a;表示用户空间且…

Flutter提示错误:无效的源发行版17

错误描述 Flutter从3.10.1 升级到3.19.4&#xff0c;在3.10.1的时候一切运行正常&#xff0c;但是当我将Flutter版本升级到3.19.4后&#xff0c;出现了下方的错误 FAILURE: Build failed with an exception.* What went wrong: Execution failed for task :device_info_plus:…

java+ssm+mysql学生信息管理系统

项目介绍&#xff1a; 使用javassmmysql开发的学生信息管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、教师、学生角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff08;可以新增管理员&#xff09;&#xff1b;专业管理&…

PCB设计规范

过孔设计 过孔盖油工艺&#xff08;也成为连塞带印&#xff09;&#xff1a;常规工艺、免费工艺&#xff0c;无特殊情况也建议使用此工艺。过孔大小建议直径在0.3mm-0.5mm之间。最省钱&#xff0c;效果最好。 非金属化槽孔 PCB制造商在加工非金属化槽孔时通常采用锣刀加工。最…

【C语言】42道大厂笔试题目(选择题)

本篇博客给大家带来的是一些大厂笔试题目&#xff0c;题目难度&#xff1a;简单&#xff0c;适合小白快速入手C语言部分的大厂笔试难度。 &#x1f41f;&#x1f41f;文章专栏&#xff1a;C语言 &#x1f680;&#x1f680;若有问题评论区下讨论&#xff0c;我会及时回答 ❤❤欢…

设置笔记本同时连接内外网

原理&#xff1a;通过笔记本和手机相连&#xff0c;实现双网卡功能能。笔记本连接内网wifi、同时手机端开启usb网络共享&#xff0c;笔记本就有了两个网&#xff0c;然配置那个访问外网&#xff0c;那个访问内网。 1.笔记本wifi连接内网wifi 2.手机端共享网络。 手机打开 -【…

JVM类加载三步解读: 双亲委派模型如何维护Java生态

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! &#x1f649;Java是面向对象编程&#xff0c;一切皆对象。这些对象是如何从一堆代码变成程序中的一部分&#xff1f;Java虚拟机&#xff08;JVM&#xff09;在这个过程中扮演了至关重要的角色。当你的代码通…