htmlanchor

背景问题和思考:序列化参数有枚举属性,序列化端增加一个枚举,能否正常反序列化?序列化子类,它和父类有同名参数,反序列化时,同名参数能否能正常赋值?序列化对象增加参数,反序列化类不增加参数,能否正常反序列化?用于序列化传输的属性,用包装器比较好,还是基本类型比较好?为什么要使用序列化和反序列化

1.程序运行过程中,产生的数据无法一直保存在内存中,需要临时或永久存储在介质(如磁盘、数据库和文件)中保存,也可能通过网络发送给合作者。要获取原始数据,程序需要从媒体或网络传输中获取。在传输过程中,只能使用二进制流进行传输。

2.简单的场景,基本类型的数据传输。通过就参数类型达成一致,数据接收者根据已建立的规则反序列化二进制流。

htmlanchor

3.在复杂场景下,数据传输的参数类型可能包括:基本类型、包装器类型、自定义类、枚举、时间类型、字符串、容器等。简单地按照惯例反序列化二进制流是很困难的。需要一个通用协议,供双方用于序列化和反序列化。

三种序列化协议及对比

串行化协议

特性

Jdk
(jdk自带)

1.序列化:静态和瞬态类型除外
2。特点:强类型,高安全性,序列化结果携带类型信息
3。反序列化:基于字段机制
4。应用场景:深度复制。

Fastjson
(第三方实现)

1.可读性好,在空
2之间占用空间小。特点:弱类型,序列化结果不携带类型信息,具有可读性。存在一些安全问题。反序列化:基于字段机制,兼容Bean机制
4。应用场景:消息,透明对象。

Hessian
(第三方实施)

1.序列化:静态和瞬态类型除外
2。特点:强类型,小尺寸,跨语言,序列化结果携带类型信息
3。反序列化:基于字段机制,兼容Bean机制
4。应用场景:RPC。

对比父亲父亲=新父亲();father.name = & # 34厨师& # 34;;father.comment = & # 34川菜馆& # 34;;father . simpleint = 1;father.boxInt =新整数(10);father . simple double = 1;father . box Double = new Double(10);father . BigDecimal = new BigDecimal(11.5);运行结果:jdk序列化结果长度:626,耗时:55jdk反序列化结果:父{version=0,name = & # 39厨师& # 39;,comment = & # 39川菜馆& # 39;,boxint = 10,simpleint = 1,boxdouble = 10.0,simpledouble = 1.0,bigdecimal = 11.5}耗时:87hessian序列化结果长度:182,耗时:56hessian反序列化结果:父{version=0,name = & # 39厨师& # 39;,comment = & # 39川菜馆& # 39;,boxint = 10,simpleint = 1,boxdouble = 10.0,simpledouble = 1.0,bigdecimal = 11.5}耗时:7Fastjson序列化结果长度:119,耗时:225Fastjson反序列化结果:父{version=0,name = & # 39厨师& # 39;,comment = & # 39川菜馆& # 39;,boxint = 10,simpleint = 1,boxdouble = 10.0,simpledouble = 1.0,bigdecimal = 11.5}耗时:69分析:jdk序列化所需时间最短,但序列化结果长度最长,是另外两者的3 ~ 5倍。Fastjson序列化结果的长度最短,但是它的时间大约是其他两个的四倍。hessian序列化的耗时和jdk相差不大,比fastjson序列化少很多。而且和jdk相比,序列化结果占用空,非常有优势。另外,hessian的反序列化速度最快,耗时是另外两个的1/10。综上所述,hessian在序列化和反序列化方面的性能最好。Hessian序列化实验准备父类公共类父实现可序列化{/* * *静态类型不会被序列化*/private Static final long serialversionuid = 1l;/** * transient将不被序列化*/transient int version = 0;/* * * name */公共字符串名称;/* * *备注*/公共字符串注释;/* * *包装类型1 */公共整数boxInt/* * *基本类型1 */public int simpleInt;/* * *包装类型2 */public Double box Double;/* * *基本类型2 */public double simple double;/* * * BigDecimal */public BigDecimal BigDecimal;public Father(){ } @ Override public String toString(){ return & # 34;父亲{ & # 34;+ "版本= & # 34;+版本+& # 34;,name = & # 39"+name+& # 39;\''+ ",comment = & # 39"+评论+& # 39;\''+ ",boxInt = & # 34+boxInt+& # 34;,simpleInt = & # 34+simpleInt+& # 34;,boxDouble = & # 34+box double+& # 34;,simpleDouble = & # 34+simple double+& # 34;,bigDecimal = & # 34+bigDecimal+& # 39;}';}}子类公共类son的名称扩展father {/* * *,与father */ public String name同名的属性;/* * *用户定义的class */ public Attributes属性;/* * * enumeration */public color;public Son(){ } } attribute-用户定义类public class attributes实现serializable { private static final long serialversionuid = 1l;公共int值;公共字符串msgpublic Attributes(){ } public Attributes(int value,String msg){ this . value = value;this.msg = msg}}枚举公共枚举颜色{RED(1,& # 34;红色& # 34;)、黄色(2、& # 34;黄色& # 34;) ;公共int值;公共字符串msgColor() { } Color(int value,String msg){ this . value = value;this.msg = msg}}使用的对象和属性设置

Son Son = new Son();son.name = & # 34厨师& # 34;;//对于与父子类同名的字段,只将son.comment = &#34赋给子类属性;川菜馆& # 34;;son . simpleint = 1;son.boxInt =新整数(10);son . simple double = 1;son . box Double = new Double(10);son . BigDecimal = new BigDecimal(11.5);son.color = Color。红色;son.attributes =新属性(11,& # 34;你好& # 34;);运行结果的分析由Hessian序列化,结果被写入一个文件并由vim打开。十六进制视图。查看命令:%!xxd

00000000:4307 6474 6f2e 536 f 6e9a 046 e 616d 6504 c . dto . son..name . 00000010:6e 61 6d 65 0763 6f6d 6d 65 6e 74 0662 6f 78 name . comment . box 000000020:496 e 7409 7369 6d 70 6c 65 496 e 7409 626 f int . simpleint . bo 00000030:7844 6f 75 626 c 650 c 7369 6d 70 6c 65 446 f x…….普通…….00000070:e9a 6 869 a 915d 0a5c 430 e 6474 6f2e 4174…..].\ c . dto . at 00000080:7472 6962 7574 6573 9205 7661 6c 75 6503贡品..value . 00000090:6d 73 6761 9b 05 6865 6c6c 6f 43 0964 746 f msga..helloc . dto 000000 a 0:2 e43 6f 6c 6f 72 9104 6e 61 6d 65 6203 5245。颜色..nameb。re 000000 b 0:4443 146 a 6176 612 e 6d 61 7468 2e 42 6967 DC . Ja . math . big 000000 c 0:4465 6369 6d 61 6c 91 0576 616 c 7565 6304十进制…Valuec.000000d0: 31312E350A11.5 .对十六进制数逐一分析,可以拆解成以下结构:参考黑森官方文档,链接:http://hessian.caucho.com/doc/hessian-serialization.html.

序列化原理序列化规则:

1.序列化的类必须实现Serializable接口。

2.静态属性和瞬态变量不会被序列化。

3.枚举类型在序列化后存储枚举变量的名称。

4.序列化结果的结构:类定义开始标识C->;类名长度+类名-& gt;属性的数量-& gt;(逐个)属性名长度+属性名-& gt;开始实例化身份-& gt;(按照属性名的顺序逐个设置属性值)(发现一个属性就是一个对象,循环这个过程)

反序列化

常见原理图:

说明:这是之前的序列化文件,你可以对照这个结构来理解反序列化的过程。

解释:读完“C”后,它知道下一步是类的定义,然后它开始读取类名、属性个数和每个属性的名称。并将该类的定义缓存在_ classDefs列表中。

说明:读取序列化文件并获取类名后,将加载该类,并生成该类的反序列化器。这里会生成一个_fieldMap,其中key是反序列化器所有属性的名称,value是属性对应的反序列化器。

说明:读取从6开始的2位十六进制数时,开始类的实例化和赋值。

遗留问题解答:增加枚举类型,反序列化不能正常读取。原因:枚举类型序列化结果中,枚举属性对应的值是枚举名。反序列化时,通过枚举类类名+枚举名反射生成枚举对象。枚举名找不到就会报错。反序列化为子类型,同名属性值无法正常赋值。序列化对象增加参数,反序列化可以正常运行。原因:反序列化时,是先通过类名加载同名类,并生成同名类的反序列化器,同名类每个属性对应的反序列化器存储在一个 map 中。在反序列化二进制文件时,通过读取到的属性名,到 map 中获取对应的反序列化器。若获取不到,默认是 NullFieldDeserializer.DESER。待到读值的时候,仅读值,不作 set 操作序列化和反序列化双方都使用对象类型时,更改属性类型,若序列化方不传输数据,序列化结果是‘N’,能正常反序列化。但是对于一方是基本类型,更改属性类型后,因为 hessian 对于基本类型使用不同范围的值域,所以无法正常序列化。

参考文档:https://zhuanlan.zhihu.com/p/44787200https://paper.seebug.org/1131/hessian 官方文档:序列化规则http://hessian.caucho.com/doc/hessian-serialization.html#anchor10ASCII 编码对照表http://ascii.911cha.com/

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

发表回复

登录后才能评论