详解JAVA序列化

news2024/10/6 14:36:17

目录

1.什么是序列化

2.JAVA中的序列化

2.1.成员变量必须可序列化

2.2.transient关键字,可避免被序列化

2.3.无法更新状态

2.4.serialVersionUID

3.JDK序列化算法

4.序列化在实际中的一些应用


 

1.什么是序列化

序列化就是将对象转换为二进制格式的过程。对象转为二进制后,可以方便进行存储或者在网络中传输。要将对象转为二进制,首先就要用一种数据结构来描述对象,这样进行对象的网络传输的时候,发送方和接收方才能按照约定好的格式来序列化、反序列化对象。不同的序列化算法就是用不同的数据结构来描述对象,序列化算法很多,这里举几个常见的:

  • json

  • xml

  • yaml

  • Java Serialization

前三种见名知意,就是分别用json、xml、yaml来描述对象,第四种Java Serialization是JDK默认的序列化算法,其使用了一种称为 Java Object Serialization Stream Protocol 的二进制格式来描述JAVA对象。

2.JAVA中的序列化

JDK种提供了Serializable接口用来声明哪些类可以被序列化,提供了ObjectOutputStream、ObjectOutputStream来进行序列化和反序列化。

JAVA的序列化中有几个注意点:

  • 成员变量必须可序列化

  • transient关键字,可避免被序列化

  • 无法更新状态

  • serialVersionUID

2.1.成员变量必须可序列化

如果所要序列化的对象的成员属性中含有对其他对象的引用,要求所引用的对象也必须是可序列化的(实现serializable接口),否则会序列化失败。

订单对象中包含一个产品对象,Order实现了序列化接口,但是product没有实现序列化接口:

25af123a84414f4eb44ae8a6a05b3cae.png

序列化Order的时候会报错:

ba7a8aaaa2044c79ba0c62b75f1ff7fd.png

2.2.transient关键字,可避免被序列化

用transient修饰属性:

46f48dc48fc04a2d8e3e6dc00dbfb82d.png

可以看到属性值不会被序列化出去,其会是默认值:

8241398ce1f247af8579efd06cfff361.png

2.3.无法更新状态

由于java序利化算法不会重复序列化同一个对象,如果对象的内容更改后,,再次序列化,并不会再次将此对象转换为字节序列。

我们对同一个对象序列化两次,然后输出其属性值:

819528be640a4caf8127f10ffa81d54c.png

可以看到其实只有第一次序列化是生效的:

a317890c83db4866b9775bf5ae6da2a5.png

2.4.serialVersionUID

序列化版本号,类似于乐观锁中的版本号,用来保证序列化后的字节序列没有被改动过,反序列化回来后和原来的程序是兼容的。

serialVersionUID不会自动改变,而是留给程序员手动更改的一个版本号标志位。更改了序列化文件的程序员一并更改版本号提示后来的人文件被更改过。

如果在反序列化时,类的 serialVersionUID 与序列化时的版本号不匹配,那么会抛出 InvalidClassException 异常,表示类的版本不兼容,无法进行反序列化。

3.JDK序列化算法

Java Object Serialization Stream Protocol规定整个对象序列化后的文件由三部分组成:

  1. 头部(Header):包含魔数(Magic Number)和版本号(Version Number)。魔数标识了该流是 Java 序列化流,版本号用于指定序列化协议的版本。

  2. 类描述符表(Class Descriptor Table):包含了序列化流中所引用的类的描述符信息。每个类描述符包括类的名称、序列化编号、序列化版本号等信息。

  3. 对象数据(Object Data):按照序列化顺序包含了被序列化对象的状态信息。这包括了对象的实例变量、类信息等。

以上一节我们在D盘下生成了一个名叫Order.txt的序列化文件为例,我们来读一读JAVA的序列化文件。

要注意的是如果直接打开,因为编码的原因看见的会是乱码,需要用16进制的方式,打开它来看看,要注意的是普通的文本工具都没办法用16进制的方式直接打开文件,这里我们用代码来将文本中的内容以16进制的方式输出,代码如下:

public static void main(String[] args) throws IOException {
        displayFileInHex("D:\\Order.txt");
    }

    private static void displayFileInHex(String filePath) throws IOException {
        try (FileInputStream fileIn = new FileInputStream(filePath)) {
            int bytesRead;
            byte[] buffer = new byte[16];

            while ((bytesRead = fileIn.read(buffer)) != -1) {
                // 打印十六进制内容
                for (int i = 0; i < bytesRead; i++) {
                    System.out.printf("%02X ", buffer[i]);
                }

                // 填充缺失的位置
                if (bytesRead < 16) {
                    int missingBytes = 16 - bytesRead;
                    for (int i = 0; i < missingBytes; i++) {
                        System.out.print("   ");
                    }
                }
                System.out.println("\n");
            }
        }
    }

输出结果:

b151542be61f438fab9edbe9a657dbce.png

用Java Object Serialization Stream Protocol来解析一下上面的字节内容:

  1. 头部(Header):AC ED 表示 Java 序列化文件的标识符。

  2. 版本号:00 05 表示版本号为 5。

  3. 对象数据:73 72 00 0E 63 6F 6D 2E 65 72 79 69 2E 4F 72 64 65 72 是一个类描述符,指明被序列化对象所属的类为 com.eryi.Order

  4. 对象数据:9D F0 BD D3 7C 8B DA 85 02 00 02 4C 00 0B 6F 72 64 65 72 4E 75 6D 62 65 72 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 是一个对象的实例数据,包含了对象的状态信息。

  5. 对象数据:4C 00 07 70 72 6F 64 75 63 74 是一个对象的实例变量的描述符,指明变量名为 product

  6. 对象数据:74 00 12 4C 63 6F 6D 2F 65 72 79 69 2F 50 72 6F 64 75 63 74 3B 是一个字符串,表示变量值为 "com.eryi.Product"

  7. 对象数据:78 70 74 00 03 34 35 36 是一个对象的实例变量的描述符,指明变量名为 xpt

  8. 对象数据:73 72 00 10 63 6F 6D 2E 65 72 79 69 2E 50 72 6F 64 75 63 74 是一个类描述符,指明变量类型为 com.eryi.Product

  9. 对象数据:15 0D 2C B6 A0 EE 95 4F 02 00 02 是一个对象的实例数据,包含了变量的状态信息。

  10. 对象数据:4C 00 04 6E 61 6D 65 是一个对象的实例变量的描述符,指明变量名为 name

  11. 对象数据:71 00 7E 00 01 是一个字符串,表示变量值为 "name"

  12. 对象数据:4C 00 05 70 72 69 63 65 是一个对象的实例变量的描述符,指明变量名为 price

  13. 对象数据:71 00 7E 00 01 是一个字符串,表示变量值为 "price"

  14. 对象数据:78 70 74 00 0C E6 B2 83 E5 B0 94 E6 B2 83 53 36 30 是一个对象的实例变量的描述符,指明变量名为 xpt

  15. 对象数据:74 00 03 33 30 57 是一个字符串,表示变量值为 "30W"

4.序列化在实际中的一些应用

首先我们要知道序列化是可以跨JVM的,JDK的序列化算法只是规定了数据结构,所以可以在一个JVM上序列化,然后在另一个JVM中进行反序列化,这也就是说序列化可以用来进行通信时的数据传输。并且序列化在进行数据传输上具有很好的性能优势,因为序列化是直接将对象转为了二进制,接收端收到数据后直接反序列化就可以得到对象。如果是以JSON之类的文本结构传输数据,那么接收端收到数据后要首先将二进制数据流转为文本结构,然后再解析文本结构将其转为对象。整个过程比起序列化和反序列化来,多了很多中间步骤,性能上肯定要慢很多。

由于序列化具有上面这样的优势,其被dubbo所采用。dubbo作为以高性能著称的RPC框架,其高性能有一方面就体现在使用了序列化上。dubbo自定义了报文,然后通过序列化的方式将数据直接塞进自定义的报文结构中,接收端收到后直接反序列化就可以得到数据。

所以序列化在追求一些高性能的通信场景下会是作为参数转换的一个不错选择。

同时,序列化又存在安全隐患,由于serialVersionUID和数据没有任何关系,修改属性的数据值后,仍然可以反序列化回来,而且任何JVM拿到序列化的数据都可以进行反序列化,会存在数据被拦截然后恶意修改的风险。不过这个问题并不是序列化所独有的问题,只要是没有加密机制的通信协议都会存在这个问题,相比于同样是透明传输的HTTP来说,用序列化在JAVA EE体系中传数据对象确实性能更优。

 

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

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

相关文章

Maven安装和配置详细教程

Maven安装和配置详细教程 1、Maven简介 Maven 是 Apache 软件基金会的一个开源项目,是一个优秀的项目构建工具,它用来帮助开发者管理项目中的 jar,以及 jar 之间的依赖关系、完成项目的编译、测试、打包和发布等工作。 2、Maven下载 点击Maven下载官方地址下载Maven。或者去…

postman持续集成-Jenkins自动构建

自动构建&#xff0c;就是设置一个定时器&#xff0c;定时时间到&#xff0c; Jenkins 自动执行测试用例 比如说,我设置下午五点,那么jenkins就是自动执行命令,自动生成报告,后续还可加上邮箱,会把报告发至邮箱 1. Jenkins 首页&#xff0c;点击任务名&#xff1a;如&#xff…

数据库—关系代数

传统的集合运算 在数据库中的关系代数运算有以下三种基本运算 并交差 必须满足两个表之间的属性个数必须一样。&#xff08;必须具有相容性&#xff09; 投影与选择运算 投影&#xff1a;π L _L L​( R ) 解释->π是投影符号&#xff0c;L是R表中的属性列&#xff0c;从…

临时文件中转服务的搭建-chfs软件的使用

因为经常用到远程桌面连接&#xff0c;所以本地pc和远程pc间的文件传输一直是个经常遇到的问题&#xff0c;尝试过用vftp搭建ftp服务&#xff0c;但是该服务在许多vps上被禁用&#xff0c;且windows上使用也要进行设置&#xff0c;比较麻烦。所幸发现了ods-im/CuteHttpFileServ…

接口测试如何做?你真的会做吗?全网超全整理实战案例...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 API测试的流程 准…

分布式事务Seate

一、Seata简介 1、Seata的核心组件 TC (Transaction Coordinator)事务协调者&#xff1a;维护全局和分支事务的状态&#xff0c;协调全局事务提交或回滚。TM (Transaction Manager)事务管理器&#xff1a;定义全局事务的范围、开始全局事务、提交或回滚全局事务。RM (Resourc…

2023下半年北京/上海/深圳软考(中/高级)认证招生

软考是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资格考试。 系统集成…

Docker安装与启动

Docker安装与启动 文章目录 Docker安装与启动前言容器与虚拟机比较 1、安装Docker2、设置ustc的镜像3、Docker的启动与停止总结 前言 容器与虚拟机比较 虚拟机&#xff08;VM&#xff09;是计算机系统的仿真。简而言之&#xff0c;它可以在实际上是一台计算机的硬件上运行看起…

Docker教程

Docker 能解决的问题 ⾸先&#xff0c;我们先来看⼏个问题&#xff1a; 1. 合作开发的时候&#xff0c;在本机可以运⾏&#xff0c;在别⼈的电脑上跑不起来。 这⾥我们以 Java Web 应⽤程序为例&#xff0c;⼀个 Java Web 应⽤程序涉及很多东⻄&#xff0c;⽐如 JDK 、 Tomc…

机器学习 day21(Tensorflow代码实现)

Tensorflow代码实现 在tensorflow中训练神经网络模型的步骤&#xff1a;第一步&#xff1a;指定模型&#xff0c;并告诉tensorflow按何种方式计算。第二步&#xff1a;使用特定的损失函数编译模型。第三步&#xff1a;训练模型

企业知识管理要怎么做,才能清晰有序?

在当今快速变化的商业环境中&#xff0c;企业知识管理的重要性日益凸显。有效的知识管理可以帮助企业整理、保存和传递知识&#xff0c;提高员工的工作效率和创新能力&#xff0c;从而为企业获得竞争优势奠定基础。本文将介绍企业在进行知识管理时应采取的措施&#xff0c;以确…

微型导轨的使用寿命能达到多久?

微型导轨&#xff0c;顾名思义就是体积很小的导轨&#xff0c;一般是应用在小型化设备中的&#xff0c;像半导体设备&#xff0c;医疗设备&#xff0c;IC制造设备&#xff0c;X-Y table&#xff0c;精密测量及检测仪器&#xff0c;高速皮带驱动设备&#xff0c;高速移载设备等都…

传说中,让测试猿分分钟心酸的五大谣言

谣传1&#xff1a;测试无聊 综观现今软件测试的一些轶事&#xff0c;我对某些错误想法的频繁出现感到吃惊。尽管有很多可以罗列&#xff0c;但是我还是想分享测试的五个最常见的谣传&#xff08;基于我短暂的经验&#xff09;。我发现前三个盛行于一些主流的新闻文章&#xff…

STM32F407系统时钟的配置和查看方法

1、系统时钟的来源 STM32F407具有两个PLL&#xff0c;用于产生不同的时钟信号。这里主要来讨论主PLL时钟。主PLL时钟的时钟源有两个信号&#xff0c;分别是上边提到的HIS信号和HSE信号。PLL通过把这两个信号倍频&#xff0c;分频等达到更高频率的时钟信号。一般来说&#xff0…

Linux6.yum,git,gdb

1.yum三板斧 yum list :显示所有能安装的软件。 yum lisy | grep 软件 :搜索软件。 yum install -y :安装软件。 yum remove -y 软件 :删除已经安装的软件。 2.git git clone 仓库网址 :添加仓库&#xff0c;按回车之后。需要输入账户和密码。 git add 文件 :把文件添加…

图像几何变换、仿射变换、透视变换

图像几何变换:平移、缩放、旋转 图像旋转变换:(x,y)为原图像坐标系,(x’,y’)为以(x0,y0)为中心的笛卡尔坐标系,图像以x0,y0)为中心进行旋转。 图像坐标系->笛卡尔坐标系->图像坐标系。如果是以图像中心旋转,则left=W/2,right=H/2,其中W和H为图像旋转…

MinGW 编译jsoncpp 的下载和编译

目录 1. jsoncpp 的下载 1.1 下载地址&#xff0c;点击可直接下载 1.2 下载完解压内容如下 2. jsoncpp 的编译 2.1 配置 2.2 生成 3. jsoncpp测试使用 1. jsoncpp 的下载 1.1 下载地址&#xff0c;点击可直接下载 mirrors / open-source-parsers / jsoncpp GitCode 1…

数据库监控与调优【十五】—— ORDER BY语句优化

ORDER BY语句优化 最好的做法&#xff1a;利用索引避免排序 实验 目的&#xff1a;哪些情况下ORDER BY子句能用索引避免排序&#xff0c;哪些情况下不能 之前说过&#xff0c;BTree数据结构里面的关键字&#xff0c;也就是索引值都是按照顺序排列的&#xff0c;那么&#xf…

端午节粽子代码(python)需要的拿走,顺带给博主一点关注呗~~~~

import math from turtle import * #胡阳 # 画粽子 def rice_dumpling():pensize(4) # 画笔宽度pencolor(4, 60, 12) # 画笔颜色fillcolor(4, 70, 19) # 填充色begin_fill()fd(200) # 向前circle(15, 120) #画圆弧fd(200)circle(15, 120)fd(200)circle(15, 120)fd(200)circle(1…

自动化测试你一定要知道的几个技巧,包你受用终身

自动化测试是应用程序在非常短的时间内执行软件的整个生命周期的过程&#xff0c;使测试软件具有很大的充分性和有效性。在这个程序设计的系统中&#xff0c;测试人员编写一个脚本&#xff0c;并借助合适的软件对软件进行测试。自动化测试背后的基本目标是提高测试效率和提高软…