java 对象序列化磁盘_java对象的序列化以及反序列化详解

2023-11-20

一、概念

序列化:把创建出来的对象(new出来的对象),以及对象中的成员变量的数据转化为字节数据,写到流中,然后存储到硬盘的文件中。

反序列化:可以把序列化后的对象(硬盘上的文件中的对象数据),读取到内存中,然后就可以直接使用对象。这样做的好处是不用再一次创建对象了,直接反序列化就可以了。

使用场景:

在创建对象并给所创建的对象赋予了值后,当前创建出来的对象是存放在堆内存中的,当JVM停止后,堆中的对象也被释放了,如果下一次想要继续使用之前的对象,需要再次创建对象并赋值。然而使用序列化对象,就可以把创建出来的对象及对象中数据存放到硬盘的文件中,下次使用的时候不用在重新赋值,而是直接读取使用即可。

对象直接转换为字节的形式进行网络传输

二、相关API介绍

序列化

序列化对象所属的类是ObjectOutputStream,如下图所示:

091d67befbb8fa840d5ce662a915f8ec.png

说明:ObjectOutputStream类可以把对象及其数据写入到流中或网络中。

构造函数如下图所示:

abe0d44be6de972fa46e21dc0050b888.png

写出功能:

92cbc1eb59ccd7071345eba29ff93b13.png

反序列化

反序列化对象所属的类是ObjectInputStream类:

5244bf76884c47652ae911a042bbbfc3.png

说明:序列化输出流对象和反序列化输出流对象都不具备读写能力,分别依赖FileOutputStream和FileInputStream类来进行读写文件。

构造函数如下图所示:

b5f224821a1258d31b5e9ac1b1466958.png

读取功能:

7ba065c57ad3da1c700e191d40a427ec.png

三、实战

序列化

需求:把Student类创建的对象持久化保存。

分析和步骤:

1)自定义一个Student类,并定义name和age属性;

2)定义一个测试类,在这个测试类中创建Student类的对象s;

3)创建序列化对象objectOutputStream,同时创建输出流并关联硬盘上的文件;

4)使用序列化对象objectOutputStream调用writeObject()函数持久化保存学生对象s;

5)释放序列化对象流的资源;

Student类如下:

需要实现序列化接口Serializable,它是一个标记性接口。这个接口中没有任何的方法,这种接口称为标记型接口!它仅仅是一个标识。只有具备了这个接口标识的类才能通过Java中的序列化和反序列化流操作这个对象。

b84ec5112d33dd7c825353731fba0388.png

/**

* 为了保证学生对象可以被序列化,我们让Student类来实现Serializable接口

*/

public class Student implements Serializable {

private String name;

private Integer age;

//省略Getter and Setter、toString和构造方法

}

测试类如下:

/**

* 将学生对象序列化持久到硬盘文件中

*/

public class ObjectOutputStreamDemo {

public static void main(String[] args) throws IOException {

//创建学生对象

Student student = new Student("张三", 13);

//把创建出来的学生对象持久化保存在硬盘中

//创建序列化对象 创建输出流对象并关联目标文件

ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\student.txt"));

//使用序列化对象中的方法持久化学生对象

objectOutputStream.writeObject(student);

//关闭资源

objectOutputStream.close();

}

}

序列化成功后在会在D盘生成一个student.txt文件。

注意:序列化对象如果没有实现序列化接口Serializable,则会抛出如下异常

ad7bd8ad1b95b5295c0ca186b03c15bd.png

反序列化

需求:把硬盘文件中的序列化的对象,再进行反序列操作。

分析和步骤:

1)创建反序列化对象,指定一个字节输入流,关联硬盘上的文件;

2)使用反序列对象调用函数readObject()函数,进行反序列操作,获得Student类的对象s;

3)使用对象s调用函数来获取Student类的name和age属性;

4)释放资源;

测试类如下:

/**

* 演示反序列化操作

*/

public class ObjectInputStreamDemo {

public static void main(String[] args) throws IOException, ClassNotFoundException {

//创建反序列化对象,指定一个字节输入流用来读取文件

ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\student.txt"));

//使用反序列化对象调用函数来进行读取数据

Student student = (Student) objectInputStream.readObject();

System.out.println(student.getName() + "," + student.getAge());

//关闭资源

objectInputStream.close();

}

}

结果:

张三,13

这里如果我们对Student类做了一些简单的修改,无关紧要的修改。例如给Student类添加一个属性字段或者函数都可以,再次反序列化,就出问题了,报如下图所示的异常:

b4ae688008c0654e37395bd004c597ba.png

ab40d9512b6b6519c157b148a23a2430.png

问题:什么是该类的序列版本号呢?

在序列化时将类的各个方面(如类的成员变量、成员函数、修饰符、函数返回值类型等)计算成为该类的默认 serialVersionUID值(版本号)。然后在序列化的时候,这个版本号会随着对象一起被序列化到本地文件中。serialVersionUID 称为序列版本编号(标记值)。类要进行序列化操作时,需要实现Serializable接口(Serializable接口也称为标记接口),实现了标记接口的类,该类会存在一个标记值。在反序列化的时候,从流中也就是硬盘文件中读取数据及原来存储的版本号。同时,再次根据类的内容计算当前的版本号。然后这两个版本号进行对比,如果不一致,认为类发生了改变,则抛出InvalidClassException异常。上述代码如果在反序列化之前修改Student类时,会在报的异常中出现如下图所示的提示信息:

local class incompatible: stream classdesc serialVersionUID = 8434462772094727595, local class serialVersionUID = 2117687252335805572

stream classdesc serialVersionUID = 8434462772094727595, 表示从流中读取的版本号(反序列化时)

local class serialVersionUID = 2117687252335805572 ,表示Student类的序列版本号(序列化时)

上述两个版本号不一致,所以报异常。

通过以上分析,可以得到一个结论:

如果可以保证反序列化对象和序列化对象的标记值相同,就可以避免异常的发生。

那么我们如何做才能保证反序列化对象和序列化对象的标记值相同呢?

我们修改Student类是无关紧要的。在我们修改Student类的时候,我们不希望它抛异常。我们可以给类定义一个默认的版本号,即给Student类添加标记值也就是版本号serialVersionUID。这样一来,添加的标记值即版本号会随着对象的序列化持久保存。无论是序列化,还是反序列化,都不会再根据类的各个方面计算版本号了。序列化和反序列化的版本号会永远一致,所以不会抛出异常,这样就可以避免InvalidClassException异常的发生了。

但是,这样一来,类的安全问题,只能自己来维护。因为已经将类的对象序列化之后,由于类中已经显示定义了版本号,那么反序列化的时候即使修改了Student类,也不会报异常了。

使用idea给自定义类Student添加版本号方法如下图所示:

98048228ec00eb46c6ae20851904a91b.png

注意:

在使用序列化操作时,不是所有的成员都可以进行序列化操作:

1)静态成员不会进行序列化操作;

2)瞬态成员也不会进行序列化操作;

瞬态成员:在进行序列化操作时,如果希望某些成员不被序列化,而该成员又不能是静态成员(不希望随着类加载而存在,和对象有关系),就使用关键字transient把成员变为瞬态成员。

代码如下所示:

2b24101e41e226646d59c3483be468fd.png

反序列化的结果:

null,null

说明:由于name和age属性分别被静态和瞬态修饰了,所以都不能被序列化到硬盘上,所以反序列化都是默认值。

记住:

1、当一个对象需要被序列化 或 反序列化的时候对象所属的类需要实现Serializable接口。

2、被序列化的类中需要添加一个serialVersionUID。

序列化的细节:

序列化的时候,只能把对象在堆中的所有数据持久保存到持久设备上。静态的成员变量不会被序列化。

有时我们在序列化的时候某些非静态成员变量也不想被序列化的时候,我们可以使用瞬态关键字(transient)修饰。

四、serialVersionUID的取值

serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。

类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。

显式地定义serialVersionUID有两种用途:

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

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

五、什么时候需要序列化对象

一:对象序列化可以实现分布式对象。

主要应用例如:RMI(即远程调用Remote Method Invocation)要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。

二:java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。

可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的"深复制",即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。

三:序列化可以将内存中的类写入文件或数据库中。

比如:将某个类序列化后存为文件,下次读取时只需将文件中的数据反序列化就可以将原先的类还原到内存中。也可以将类序列化为流数据进行传输。总的来说就是将一个已经实例化的类转成文件存储,下次需要实例化的时候只要反序列化即可将类实例化到内存中并保留序列化时类中的所有变量和状态。

四: 对象、文件、数据,有许多不同的格式,很难统一传输和保存。

序列化以后就都是字节流了,无论原来是什么东西,都能变成一样的东西,就可以进行通用的格式传输或保存,传输结束以后,要再次使用,就进行反序列化还原,这样对象还是对象,文件还是文件

正常来说是很少需要用到的,大部分情况下我们都是使用json或者xml格式来进行数据传输,如果只是转换为字符串的形式与网络打交道,那么就不需要实现Serializable接口。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 对象序列化磁盘_java对象的序列化以及反序列化详解 的相关文章

  • Ridis持久化

    Redis持久化 RDB Redis DataBase Redis会单独创建 fork 一个子进程来进行持久化 会先将数据写入到一个临时文件中 待持久化都结束了 再用这个临时文件替换上次持久化好的文件 整个过程中 主进程是不进行io操作的
  • 8--UI 初步认识 简易计算器

    UI是App的根基 一个App应该是先有UI界面 然后在UI的基础上增加实用功能 2 UI相对简单易学 UI普遍是学习过程中最简单的一块 能快速拥有成就感和学习兴趣 3 UI至关重要 开发中的绝大部分时间都在处理UI 谨记一条IOS软件开发
  • MySQL根据某一个或者多个字段查找重复数据

    sql 查出一张表中重复的所有记录数据 1 表中有id和name 两个字段 查询出name重复的所有数据 select from xi a where a username in select username from xi group
  • 系列教程

    PDF Search 系列教程来咯 在 Part 1 中 我们将演示如何从 PDF 中提取 处理并存储图像及文本 随着神经搜索 Neural Search 技术的普及 越来越多开发者 开始尝试用 Jina 解决非结构化数据的索引和搜索问题
  • MySQL必知必会 学习笔记 第二十五章 使用触发器

    触发器在MySQL 5中增加 触发器可以在MySQL响应DELETE INSERT UPDATE语句时自动执行一条SQL语句 MySQL 5中触发器名在每个表中唯一而不是在一个数据库中唯一 其他DBMS有的重名限制是数据库范围 以后MySQ
  • lua和测试(一)

    lua做为一门高级语言 在游戏产业运用到机会越来越多了 测试掌握几门脚本语言也有一定的重要性 以下对于lua组合输入做出一些引导 测试需要掌握的关于返回数值 主要用到布尔类 前言的指引 lua的语法比较简单和清晰 学过c语言的可以很好的掌握
  • 并发编程系列之自定义线程池

    前言 前面我们在讲并发工具类的时候 多次提到线程池 今天我们就来走进线程池的旅地 首先我们先不讲线程池框架Executors 我们今天先来介绍如何自己定义一个线程池 是不是已经迫不及待了 那么就让我们开启今天的旅途吧 什么是线程池 线程池可
  • selenium+python 对输入框的输入处理

    最近自己在做项目的自动化测试 公司无此要求 在用户管理模块做修改用户信息时 脚本已经跑成功 并且的确做了update操作 但是自己登陆页面检查 信息却没有被修改 再次确定系统该模块的编辑功能可用 脚本如下 if result num gt
  • 近千万EOS被盗事件回顾,大家请保护好自己的EOS私钥

    最近有伙伴被盗了价值近千万的EOS 于是查看了这次被盗活动账号记录 这次分享出来 一是有可能大家有线索 二是也让大家意识到数字货币私钥安全的重要性 事件回顾 受害人在7 9号被偷盗人通过update auth更换了账号授权公私钥 紧接着被转
  • 零基础到GPT高手:快速学习与利用ChatGPT的完全指南

    进入人工智能时代 令人惊叹的ChatGPT技术正在引爆全球 您是否想象过能够与智能语言模型对话 提升工作效率 解锁创意 甚至实现商业化变现 在本篇文章中 我将向你揭示ChatGPT的原理 学习技巧 并展示如何利用ChatGPT提升工作效率和
  • Windows11:QT5.14.2+PCL1.12.0+VS2019环境配置

    之前在win10系统下配置了PCL1 8 1 QT5 9 1 VS2015的开发环境 由于PCL库已经更新到了1 12 1而且1 8 1一直有bug 为了使用下新的算法库 今天配置一下新的开发环境 1 安装Qt5 14 2 Qt5 14 2
  • 【b站雅思笔记】Simon‘s IELTS Course - 听力部分

    前情提要 b站up主贼开心的小林上传的Simon的听力课 资料均来源于她 参考 雅思阅读 最好的雅思课程 阅读部分全集 https www bilibili com video BV1ea4y1x7qR spm id from 333 78
  • Spring为什么要用的三级缓存解决循环依赖

    一 代码准备 Component aService public class AService Autowired private BService bService public void test System out println
  • 哈工大2020软件构造Lab3实验报告

    本项目于4 21日实验课验收 更新完成 如果有所参考 请点点关注 点点赞GitHub Follow一下谢谢 2020春计算机学院 软件构造 课程Lab3实验报告 Software Construction 2020 Spring Lab 3
  • react_hooks系列05_useRef,useImperativeHandle,高阶组件forwordRef

    一 useRef 1 uesRef使用在官方标签上 useRef 返回一个可变的 ref 对象 其 ref 对象 current 属性被初始化为传入的参数 initialValue 返回的 ref 对象在组件的整个生命周期内保持不变 imp
  • 蓝桥杯字母阵列

    字母阵列 递归解法 仔细寻找 会发现 在下面的8x8的方阵中 隐藏着字母序列 LANQIAO SLANQIAO ZOEXCCGB MOAYWKHI BCCIPLJQ SLANQIAO RSFWFNYA XIFZVWAL COAIQNAL 我
  • 教你怎么导入导出数据

    最近在做一个项目 需要对数据进行导入导出 实现之后 自己也做了一个总结 总体来说还是比较容易的 第一次的话肯定有许多坑的 细节真的很重要 当你踏过一个又一个坑 一路路走来 你会发现自己的信心越来越强 对于数据的导入导出 我们首先写一个工具类
  • 代码检查、评审、单元测试工具 大搜集

    看书真是迅速进入一个陌生领域的最快办法 系统的 体系完整的知识比起在互联网上七拼八凑出的认识强太多了 先记下一些理论概念 软件生命周期模型 分析 设计与文档 编码与审查 测试与调试 发布与维护 软件测试对象的6种分类 单元测试 静态检查 动
  • 数据结构---线性表的静态/动态分配与顺序/链式存储

    线性表 基于严魏敏版数据结构c语言实现 谭浩强版c语言 数据元素在计算机中的存储分为顺序存储和链式存储 顺序存储 借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系 链式存储 借助指示元素存储地址的指针表示数据元素之间的逻辑关系 ps

随机推荐

  • matlab定义机器人位置,机器人自定位问题(数学建模)

    形形色色 各式各样的机器人正在走进人们的生产与生活 发挥着越来越重要的作用 这些机器人 一般都拥有 感官 各种传感器 大脑 智能计算的软硬件 和 执行器 各种操控设备 等 它们在自己的工作场合内 能自主感知 自主决策并完成使命 为达到这样的
  • 笔记---Linux安装OpenCV及VSCode的配置编译

    学更好的别人 做更好的自己 微卡智享 本文长度为4250字 预计阅读10分钟 前言 最近在学点新东西 教程中主要也是在Linux中使用 对于我这个以前从未接触Linux系统的人来说 正好也是个机会掌握下LInux系统 这篇就是记录在Linu
  • 批量创建文件与文件夹

    1 批量创建文件 下面们来说一下如何在pyhton中去批量创建文件 假设我要新建10个txt文件 这里我用一个for循环 for i in range 10 这里的 指代的是当前文件夹 i表示文件的名称 a表示没有该文件就新建 f open
  • Java 泛型 T,E,K,V,?

    泛型带来的好处 在没有泛型的情况的下 通过对类型 Object 的引用来实现参数的 任意化 任意化 带来的缺点是要做显式的强制类型转换 而这种转换是要求开发者对实际参数类型可以预知的情况下进行的 对于强制类型转换错误的情况 编译器可能不提示
  • 入门力扣自学笔记279 C++ (题目编号:1123)

    1123 最深叶节点的最近公共祖先 题目 给你一个有根节点 root 的二叉树 返回它 最深的叶节点的最近公共祖先 回想一下 叶节点 是二叉树中没有子节点的节点 树的根节点的 深度 为 0 如果某一节点的深度为 d 那它的子节点的深度就是
  • python 实现 softmax分类器(MNIST数据集)

    最近一直在外面 李航那本书没带在身上 所以那本书的算法实现估计要拖后了 这几天在看Andrew Ng 机器学习的课程视频 正好看到了Softmax分类器那块 发现自己之前理解perceptron与logistic regression是有问
  • JSTL和EL:

    El表达式使JSP的开发变得更加简单 简介 什么是EL Expression Language 表达式语言 El得功能 代替JSP页面中数据访问时得代码复杂编程 EL得特点 自动转换类型 EL得到某个数据时可以自动转换类型 使用简单 EL表
  • 【微信小程序】数组排序以及去重问题详解

    微信小程序中 通常有一些数据 是存在前端缓存里的 但是这个数据如果是没有处理过 需要动态处理的时候 数据就会有问题 所以 提供一些数据的几种处理方式 二维数组排序 var arr1 new Array arr1 中猫猫er E7555大号
  • FineReport 帆软实战一 帆软概述及软件下载

    前言 公司近期引进帆软报表替换原先的润乾报表 以提供更为强大的报表处理能力 因此我也开始从零学习帆软报表 帆软报表报表分为FineReport和FineBI Report可以理解为面向开发人员的报表设计器 用于开发复杂类型的报表 需要开发人
  • 计算机中的二进制表示-4和5

    十进制 二进制 5 00000000 00000000 00000000 00000101 4 11111111 11111111 11111111 11111100 负数的二进制如何得出 相信正数的二进制表示大家都懂 但是这个 4怎么来的
  • 一文教你如何在HBuilderX中使用模拟器开发调试App

    一文教你如何在HBuilderX中使用模拟器开发调试App 第一步下载HBuilderX 第二步 下载一个模拟器 这里我选择的是网易出品的mumu模拟器 第三步 打开上面安装的两个软件 接着在hbx里运行到模拟器 如下图所示 如果和图片中一
  • 从12306验证码看人工智能未来发展

    事件背景 最近12306对登陆验证过程进行了升级 让很多抢票软件失效 也引起众多网友的热议 如图 用户在登陆时需要选择和题目给出的描述相同的图片 新的验证方式推出后 不少网友也在网上发表看法 大部分网友表示此举很给力 黄牛抢票软件失效了 对
  • mysql dump 导出表_[译文]MySQL中快速逻辑备份一张单独的表

    逻辑备份在跨云环境的数据迁移和表级恢复中非常有用 8 0 22的MySQL shell引入了两个新的实用程序util dumpTable 和util exportTable 用于从MySQL中导出单独的表 在8 0 22之前 无法使用MyS
  • 电脑提示vcomp140.dll无法继续执行代码

    电脑提示vcomp140 dll无法继续执行代码怎么办 vcomp140 dll是电脑系统系统重要的动态链接库文件 丢失或者损坏的话 会导致电脑很多软件跟游戏无法打开运行 需要怎么修复 详细困扰着不少小伙伴 小编今天就把教程分享给大家 修复
  • 2.0生命周期 fabric java 链码安装

    2 0生命周期 fabric java 链码安装 步骤
  • ATT&CK红队评估实战靶场-1(全网最细)

    声明 该系列文章首发于公众号 Y1X1n安全 转载请注明出处 本公众号所分享内容仅用于网安爱好者之间的技术讨论 所有渗透及工具的使用都需获取授权 禁止用于违法途径 否则需自行承担 本公众号及作者不承担相应的后果 ATT CK红队评估实战靶场
  • 列表 元组和字典

    1 列表 1 1列表的循环变量 for循环 while循环 1 2列表常见的操作 1 2 1在列表增加元素 append方法 extend方法 insert方法 append方法 在列表的末尾新增元素 extend方法 将一个列表中的元素全
  • Golang协程与通道整理

    协程goroutine 不由OS调度 而是用户层自行释放CPU 从而在执行体之间切换 Go在底层进行协助实现 涉及系统调用的地方由Go标准库协助释放CPU 总之 不通过OS进行切换 自行切换 系统运行开支大大降低 通道channel 并发编
  • 求一个数组的最大值最小值及其下标

    求一个数组的最大值最小值及其下标 思路 假定一个数为最大值 如果有个数比假定的最大值还大 那么该数就为最大值 最小值同理 使用for循环 public class MaxMin public static void main String
  • java 对象序列化磁盘_java对象的序列化以及反序列化详解

    一 概念 序列化 把创建出来的对象 new出来的对象 以及对象中的成员变量的数据转化为字节数据 写到流中 然后存储到硬盘的文件中 反序列化 可以把序列化后的对象 硬盘上的文件中的对象数据 读取到内存中 然后就可以直接使用对象 这样做的好处是