java基础之序列化
转载自https://www.cnblogs.com/szlbm/p/5504166.html
Java对象表示方式1:序列化、反序列化和transient关键字的作用
平时我们在Java内存中的对象,是无 法进行IO操作或者网络通信的,因为在进行IO操作或者网络通信的时候,人家根本不知道内存中的对象是个什么东西,因此必须将对象以某种方式表示出来,即 存储对象中的状态。一个Java对象的表示有各种各样的方式,Java本身也提供给了用户一种表示对象的方式,那就是序列化。换句话说,序列化只是表示对 象的一种方式而已。OK,有了序列化,那么必然有反序列化,我们先看一下序列化、反序列化是什么意思。
序列化:将一个对象转换成一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的。
反序列化:将字节数组重新构造成对象。
默认序列化
序列化只需要实现java.io.Serializable接口就可以了。序列化的时候有一个serialVersionUID参数,Java序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。 在进行反序列化,Java虚拟机会把传过来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较, 如果相同就认为是一致的实体类,可以进行反序列化,否则Java虚拟机会拒绝对这个实体类进行反序列化并抛出异常。serialVersionUID有两 种生成方式:
1、默认的1L
2、根据类名、接口名、成员方法以及属性等来生成一个64位的Hash字段
如果实现 java.io.Serializable接口的实体类没有显式定义一个名为serialVersionUID、类型为long的变量时,Java序列化 机制会根据编译的.class文件自动生成一个serialVersionUID,如果.class文件没有变化,那么就算编译再多 次,serialVersionUID也不会变化。换言之,Java为用户定义了默认的序列化、反序列化方法,其实就是ObjectOutputStream的defaultWriteObject方法和ObjectInputStream的defaultReadObject方法。看一个例子:
按 Ctrl+C 复制代码 按 Ctrl+C 复制代码
先不运行,用一个二进制查看器查看一下s.txt这个文件,并详细解释一下每一部分的内容。
第1部分是序列化文件头
◇AC ED:STREAM_MAGIC序列化协议
◇00 05:STREAM_VERSION序列化协议版本
◇73:TC_OBJECT声明这是一个新的对象
第2部分是要序列化的类的描述,在这里是SerializableObject类
◇72:TC_CLASSDESC声明这里开始一个新的class
◇00 1F:十进制的31,表示class名字的长度是31个字节
◇63 6F 6D ... 65 63 74:表示的是“com.xrq.test.SerializableObject”这一串字符,可以数一下确实是31个字节
◇00 00 00 00 00 00 00 01:SerialVersion,序列化ID,1
◇02:标记号,声明该对象支持序列化
◇00 01:该类所包含的域的个数为1个
第3部分是对象中各个属性项的描述
◇4C:字符"L",表示该属性是一个对象类型而不是一个基本类型
◇00 04:十进制的4,表示属性名的长度
◇73 74 72 30:字符串“str0”,属性名
◇74:TC_STRING,代表一个new String,用String来引用对象
第4部分是该对象父类的信息,如果没有父类就没有这部分。有父类和第2部分差不多
◇00 12:十进制的18,表示父类的长度
◇4C 6A 61 ... 6E 67 3B:“L/java/lang/String;”表示的是父类属性
◇78:TC_ENDBLOCKDATA,对象块结束的标志
◇70:TC_NULL,说明没有其他超类的标志
第5部分输出对象的属性项的实际值,如果属性项是一个对象,这里还将序列化这个对象,规则和第2部分一样
◇00 04:十进制的4,属性的长度
◇73 74 72 30:字符串“str0”,str0的属性值
从以上对于序列化后的二进制文件的解析,我们可以得出以下几个关键的结论:
1、序列化之后保存的是类的信息
2、被声明为transient的属性不会被序列化,这就是transient关键字的作用
3、被声明为static的属性不会被序列化,这个问题可以这么理解,序列化保存的是对象的状态,但是static修饰的变量是属于类的而不是属于变量的,因此序列化的时候不会序列化它
接下来运行一下上面的代码看一下
str0 = str0
str1 = null
因为str1是一个transient类型的变量,没有被序列化,因此反序列化出来也是没有任何内容的,显示的null,符合我们的结论。
手动指定序列化过程
Java并不强求用户非要使用默认的序列化方式,用户也可以按照自己的喜好自己指定自己想要的序列化方式----只要你自己能保证序列化前后能得到想要的数据就好了。手动指定序列化方式的规则是:
进 行序列化、反序列化时,虚拟机会首先试图调用对象里的writeObject和readObject方法,进行用户自定义的序列化和反序列化。如果没有这 样的方法,那么默认调用的是ObjectOutputStream的defaultWriteObject以及ObjectInputStream的 defaultReadObject方法。换言之,利用自定义的writeObject方法和readObject方法,用户可以自己控制序列化和反序列 化的过程。
这是非常有用的。比如:
1、有些 场景下,某些字段我们并不想要使用Java提供给我们的序列化方式,而是想要以自定义的方式去序列化它,比如ArrayList的 elementData、HashMap的table(至于为什么在之后写这两个类的时候会解释原因),就可以通过将这些字段声明为transient, 然后在writeObject和readObject中去使用自己想要的方式去序列化它们
2、因为 序列化并不安全,因此有些场景下我们需要对一些敏感字段进行加密再序列化,然后再反序列化的时候按照同样的方式进行解密,就在一定程度上保证了安全性了。 要这么做,就必须自己写writeObject和readObject,writeObject方法在序列化前对字段加密,readObject方法在序 列化之后对字段解密
上面的例子SerializObject这个类修改一下,主函数不需要修改:
直接看一下运行结果
我想自己控制序列化的过程
我想自己控制反序列化的过程
str0 = str0
str1 = str1
看到,程序走到了我们自己写的writeObject和readObject中,而且被transient修饰的str1也成功序列化、反序列化出来了----因为手动将str1写入了文件和从文件中读了出来。不妨再看一下s.txt文件的二进制:
看到橘黄色的部分就是writeObject方法追加的str1的内容。至此,总结一下writeObject和readObject的通常用法:
先通过defaultWriteObject和defaultReadObject方法序列化、反序列化对象,然后在文件结尾追加需要额外序列化的内容/从文件的结尾读取额外需要读取的内容。
复杂序列化情况总结
虽然Java的序列化能够保证对象状态的持久保存,但是遇到一些对象结构复杂的情况还是比较难处理的,最后对一些复杂的对象情况作一个总结:
1、当父类继承Serializable接口时,所有子类都可以被序列化
2、子类实现了Serializable接口,父类没有,父类中的属性不能序列化(不报错,数据丢失),但是在子类中属性仍能正确序列化
3、如果序列化的属性是对象,则这个对象也必须实现Serializable接口,否则会报错
4、反序列化时,如果对象的属性有修改或删减,则修改的部分属性会丢失,但不会报错
5、反序列化时,如果serialVersionUID被修改,则反序列化时会失败
java基础之序列化的更多相关文章
- 【Java基础】序列化与反序列化深入分析
一.前言 复习Java基础知识点的序列化与反序列化过程,整理了如下学习笔记. 二.为什么需要序列化与反序列化 程序运行时,只要需要,对象可以一直存在,并且我们可以随时访问对象的一些状态信息,如果程序终 ...
- Java基础系列——序列化(一)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6797659.html 工作中发现,自己对Java的了解还很片面,没有深入的研究,有很多的J ...
- JAVA基础之——序列化和反序列化
1 概念 序列化,将java对象转换成字节序列的过程. 反序列化,将字节序列恢复成java对象的过程. 2 为什么要序列化? 2.1 实现数据持久化,当对象创建后,它就会一直在,但是在程序终止时,这个 ...
- java基础知识-序列化/反序列化-gson基础知识
以下内容来之官网翻译,地址 1.Gson依赖 1.1.Gradle/Android dependencies { implementation 'com.google.code.gson:gson:2 ...
- java基础之 序列化
一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬 ...
- Java基础之序列化对象——将对象写入到文件中(SerializeObjects)
控制台程序. 首先定义一个含有任意不同数据类型域的可序列化类: import java.io.Serializable; public class Junk implements Serializab ...
- JAVA基础之序列化与反序列化
序列化和反序列化: 把对象转化为字节序列的过程称为序列化: 把字节序列恢复为对象的过程称为对象的反序列化: 方法: Java.io.ObjectOutputStream代表对象的输出流,writeOb ...
- Java基础知识➣序列化与反序列化(四)
概述 Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据.有关对象的类型的信息和存储在对象中数据的类型. 将序列化对象写入文件之后,可以从文件 ...
- Java基础教程——序列化
序列化 序列化:Serialize,将Java对象写入IO流(可以保存在数据库,文件等) 反序列化:Deserialize,从IO流中读取并恢复Java对象. 这么理解:序列化就是把对象封印起来,反序 ...
随机推荐
- idea配置opencv
参考:https://blog.csdn.net/sinat_38102206/article/details/81156589 配置运行时参数.通过菜单“Run->Edit Configura ...
- StructuredStreaming(New)
SparkStreaming API using DataSets and DataFrames (New) 使用流式DataSets和流式DataFrames的API ◆ 1.创建流式DataFr ...
- echars 饼图使用
option = { tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d ...
- 发布 npm遇到的问题
npm publish 遇到 403 怎么办? 这说明你没有切换到 npm 原始源,那么你只需要用 npm config delete registry 删除淘宝源,然后再 publish. publ ...
- Newbe.Claptrap 框架入门,第三步 —— 定义 Claptrap,管理商品库存
接上一篇 Newbe.Claptrap 框架入门,第二步 —— 简单业务,清空购物车 ,我们继续要了解一下如何使用 Newbe.Claptrap 框架开发业务.通过本篇阅读,您便可以开始学会添加一个全 ...
- openssh一键升级脚本(只升级openssh,其它已有环境不变,解决root登录问题)
#!/bin/bash ################################################################# ###### update openssl ...
- websocket学习(转载)
public interface WebSocketMessageBrokerConfigurer { // 添加这个Endpoint,这样在网页中就可以通过websocket连接上服务,也就是我们配 ...
- 无法登陆网站,nginx漏配置
location / { try_files $uri $uri/ /index.php?$query_string; } 这条主要是将index.php入口文件重写掉,所以平常我 ...
- Unable to add window -- token null is not for an application错误的解决方法 android开发
Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not f ...
- jumpserver如何在远程时使用复制粘贴-windwos系统下
jumpserver堡垒机搭建好了,但是在使用的时候,有时候会出现远程下不能复制粘贴,这让体验十分不爽. 于是着手解决这个问题,附上参考链接,感谢大佬:http://itren.xiaolee.net ...