序列化和反序列化的底层实现原理是什么?

article/2025/9/16 13:28:42

序列化和反序列化作为Java里一个较为基础的知识点,大家心里也有那么几句要说的,但我相信很多小伙伴掌握的也就是那么几句而已,如果再深究问一下Java如何实现序列化和反序列化的,就可能不知所措了!遥记当年也被问了这一个问题,自信满满的说了一大堆,什么是序列化、什么是反序列化、什么场景的时候才会用到等,然后面试官说:那你能说一下序列化和反序列化底层是如何实现的吗?一脸懵逼,然后回家等通知!

一、基本概念

1、什么是序列化和反序列化

(1)Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程;

(2)**序列化:**对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。

(3)**反序列化:**客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。

(4)本质上讲,序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态。

2、为什么需要序列化与反序列化

我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。

那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的!如何做到呢?这就需要Java序列化与反序列化了!

换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。

总的来说可以归结为以下几点:

(1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;
(2)通过序列化以字节流的形式使对象在网络中进行传递和接收;
(3)通过序列化在进程间传递对象;

3、序列化算法一般会按步骤做如下事情:

(1)将对象实例相关的类元数据输出。
(2)递归地输出类的超类描述直到不再有超类。
(3)类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
(4)从上至下递归输出实例的数据

二、Java如何实现序列化和反序列化

1、JDK类库中序列化和反序列化API

(1)java.io.ObjectOutputStream:表示对象输出流;

它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;

(2)java.io.ObjectInputStream:表示对象输入流;

它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回;

2、实现序列化的要求

只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常!

3、实现Java对象序列化与反序列化的方法

假定一个User类,它的对象需要序列化,可以有如下三种方法:

(1)若User类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化

ObjectOutputStream采用默认的序列化方式,对User对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对User对象的非transient的实例变量进行反序列化。

(2)若User类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用User对象的readObject(ObjectInputStream in)的方法进行反序列化。

(3)若User类实现了Externalnalizable接口,且User类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用User对象的readExternal(ObjectInput in)的方法进行反序列化。

4、JDK类库中序列化的步骤

步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\object.out"));

步骤二:通过对象输出流的writeObject()方法写对象:

oos.writeObject(new User("xuliugen", "123456", "male"));

5、JDK类库中反序列化的步骤

步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:

ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));

步骤二:通过对象输出流的readObject()方法读取对象:

User user = (User) ois.readObject();

说明:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。

6、序列化和反序列化的示例

为了更好地理解Java序列化与反序列化,举一个简单的示例如下:

public class SerialDemo {public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化FileOutputStream fos = new FileOutputStream("object.out");ObjectOutputStream oos = new ObjectOutputStream(fos);User user1 = new User("xuliugen", "123456", "male");oos.writeObject(user1);oos.flush();oos.close();//反序列化FileInputStream fis = new FileInputStream("object.out");ObjectInputStream ois = new ObjectInputStream(fis);User user2 = (User) ois.readObject();System.out.println(user2.getUserName()+ " " + user2.getPassword() + " " + user2.getSex());//反序列化的输出结果为:xuliugen 123456 male}
}public class User implements Serializable {private String userName;private String password;private String sex;//全参构造方法、get和set方法省略
}

object.out文件如下(使用UltraEdit打开):

这里写图片描述

注:上图中0000000h-000000c0h表示行号;0-f表示列;行后面的文字表示对这行16进制的解释;对上述字节码所表述的内容感兴趣的可以对照相关的资料,查阅一下每一个字符代表的含义,这里不在探讨!

类似于我们Java代码编译之后的.class文件,每一个字符都代表一定的含义。序列化和反序列化的过程就是生成和解析上述字符的过程!

序列化图示:

这里写图片描述

反序列化图示:

这里写图片描述

三、相关注意事项

1、序列化时,只对对象的状态进行保存,而不管对象的方法;

2、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

3、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

4、并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

  • 安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

  • 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

5、声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。

6、序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途:

  • 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

  • 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

7、Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;

8、如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因;

四、总结

看到这里,可能已经让我们很满足了,毕竟已经知道了我们平时使用的序列化和反序列化是如何进行操作的,Java给我们提供了哪些接口可供使用,也比我们最初知道的简单的什么是序列化、反序列化以及作用多了很多!后续内容我们也会不断在讨论和更新!


参考文章:

1、https://zhidao.baidu.com/question/688891250408618484.html
2、https://blog.csdn.net/morethinkmoretry/article/details/5929345
3、https://www.jianshu.com/p/edcf7bd2c085
4、https://blog.csdn.net/xiaocaidexuexibiji/article/details/22692097

在这里插入图片描述

【视频福利】2T免费学习视频,搜索或扫描上述二维码关注微信公众号:Java后端技术(ID: JavaITWork)回复:1024,即可免费获取!内含SSM、Spring全家桶、微服务、MySQL、MyCat、集群、分布式、中间件、Linux、网络、多线程,Jenkins、Nexus、Docker、ELK等等免费学习视频,持续更新!


http://chatgpt.dhexx.cn/article/ac3xfXD9.shtml

相关文章

序列化和反序列化

我以前确实对序列化,乃至现在也是不是很熟悉,有时候查找资料,但依旧懵懵懂懂,不过还好遇到一个博主,确定写的挺好的,链接会放再底部 废话不多说,先看官网定义: 序列化 (Serializat…

我把序列化玩成了这样,吊锤了一波面试官

我们都知道,新建一个对象的时候实现 Serializeable 接口,但为什么要这么做?什么时候这样子做?这样子做会不会出现幺蛾子?阿粉一个三连差点把自己都问懵逼了…… 那接下来,大家就和阿粉一起简单了解一下这个…

什么是序列化? 如何实现(反)序列化 序列化的应用

1. 什么是序列化与反序列化,什么情况需要序列化1.1 序列化序列化是什么序列化的目的什么情况需要序列化 1.2 反序列化反序列化是什么反序列化的目的 2. Java中的序列化与反序列化2.1 如何实现序列化Java序列化的规定序列化的API实现(反)序列化的示例对象在硬盘上的存…

1.传输线驻波比

Transmission Line & Active Voltage Standing Wave Ratio 1.1 信号完整性概述 数字电路的出现极大地提高了电子产品的抗干扰能力,随着电路的工作频率不断提高,这种抗干扰能力逐渐显得有些“力不从心”。特别是在高速电路的范畴,“理想互…

驻波比,功率计原理,短波机驻波测量

文章内容转载自http://bbs.cqcqcq.com/thread-1627-1-1.html 衡量功率反射大小的量称为「反射系数」,常用Γ (音 gamma) 或ρ (音 rho) 表示。为了讨论简单起见,我们假设负载阻抗为纯阻性的。反射系数定义为: ρ (反射电压波) / (入射电压波)…

入射波反射波和驻波的特性推导

入射波反射波和驻波的基本推导 学习雷达过程中,发现阻抗匹配是一道迈不过去的坎,而阻抗匹配、能量传输与电压驻波比又有千丝万缕的联系,而电压驻波比则与反射波、入射波等相关的特性有关,于是写下此文章记录一下推导过程。 懒得正…

反射系数、驻波比、S参数之间的关系

反射系数、驻波比、S参数之间的关系! 转载▼ 回波损耗(Return Loss): 入射功率/反射功率, 为dB数值 反射系数(Г): 反射电压/入射电压, 为标量 电压驻波比(Voltage Standing Wave Ration): 波腹电压/波节电压 S参数: S12为反向传输系数,也就是隔离。…

馈线中的VSWR电压驻波比

在射频信号馈线传输中,信号传输有一个概念:驻波比。 这个概念好理解,就是一个波进去,在终端由于不匹配形成反射波回来。 但是不是那么好想像,叠加后是啥模样的波形。 借助pythonmatplotlib可以方便模拟出来&#xf…

简单了解什么是驻波比?

驻波比全称为电压驻波比,又名VSWR,为英文Voltage Standing Wave Ratio的简写,在理解电压驻波比之前先要明白什么是“驻波”。 假设两个波长相同的波以相反的方向传播,绿线波朝着左方向旋转,蓝线波朝着右方向旋转&…

驻波比理解

VSWR(Voltage Standing Wave Ratio)代表电压驻波比。要完全理解这个术语,需要知道什么是“驻波”。 假设两个波长相同的波以相反的方向传播,如下所示。一个波表示为蓝线,它朝着正确的方向旋转。另一个波用绿线表示,它在左方向旋转…

电压驻波比,回波损耗,传输损耗,电压反射系数,功率传输,功率反射换算表

回波损耗(Return Loss):入射功率/反射功率, 为dB数值反射系数(Г):反射电压/入射电压, 为标量电压驻波比(Voltage Standing Wave Ration): 波腹电压/波节电压S参数:S12为反向传输系数,也就是隔离。S21为正向传输系数,也…

天线的驻波比

驻波比是衡量天线性能的重要参数之一,体现了天线向外界空间辐射能量的潜力。这是一个标量的参数,还有史密斯圆图(the Smith Chart)来衡量天线的阻抗特性,可以分析天线是感性还是容性的,并指明了调整天线的方向。 目录​ 一、什么是驻波比VSWR或者SWR

关于驻波比(VSWR)的详细解析

from滤波器 ◆ ◆ ◆ 文 | 滤波器(ID:Filter_CN) 驻波比(VSWR)用来检测天馈线系统、射频接头以及所有的连接到基站的射频设备的工作状态。VSWR过高会导致掉话、高误码率,而且由此引入的发射/接受功率的衰减会导致小…

射频回波损耗、反射系数、电压驻波比、S参数的含义与关系

以二端口网络为例,如单根传输线,共有四个S参数:S11,S12,S21,S22,对于互易网络有S12=S21,对于对称网络有S11=S22,对于无耗网络,有S11*S…

【回波损耗(dB)和电压驻波比(VSWR)之间的关系】

回波损耗(dB)和电压驻波比(VSWR)之间的关系 反射系数(Г / Rho) Г=反射波振幅/入射波振幅 =(传输线特性阻抗-负载阻抗) / (传输线特性阻抗负载阻抗) 回波损耗( RL ) 回波损耗: 回波损耗,又称为反射损…

RF(射频) - VSWR(电压驻波比)

VSWR代表电压驻波比(Voltage Standing Wave Ratio)。要完全理解这个术语,你需要知道什么是“驻波”。 你可能已经在高中物理课上学到了驻波。只要刷新你的想法,让我解释一下驻波是什么。 假设具有相同波长的两个波沿相反方向传播…

天线参数-自用1

天线参数 1丶 天线谐振频率 Resonance Frequency 2丶驻波比 指的是行驻波的电压波腹值和电压波节值之比 2.1 驻波 驻波即两个反方向波的合成波形,该合成波相位不变,幅度变化,节点位置(值 0)不会发生变化。 幅度最大…

内联函数(inline)总结

1:定义: 它们看起来象函数,运作起来象函数,比宏(macro)要好得多,使用时还不需要承担函数调用的开销。当内联一个函数时,编译器可以对函数体执行特定环境下的优化工作。这样的优化对"正常"的…

【C++】内联函数理解

内联函数 内联函数的使用是对于C语言中宏函数的一种改进,他继承了宏的优点并避免了宏的缺点。 宏的优点:a. 代码复用性高 b. 宏函数减少栈帧建立,提高效率 宏的缺点:a. 可读性差 b. 没有类型安全检查 c. 不方便调试 C基本不再建议…

在什么情况下方法调用会被内联?

写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见100个问题搞定Java虚拟机 解答 方法内联有许多规则。…