序列化和反序列本质上就是对象和字节数组的转换:
序列化时,将Java对象编码为byte数组
反序列化,则是将byte数组转换为Java对象
序列化用途: 1、在网络上传送对象的字节序列
2、把对象的字节序列永久地保存到硬盘上,通常放在一个文件中
1、ObjectOutputStream:通过writeObject方法将对象序列化,并将得到的字节序列写到目标输出流
try { ObjectOutputStream output =new ObjectOutputStream(new FileOutputStream("oppo.text")); output.writeObject(new Regulation<>()); }catch (Exception e){ }
2、ObjectInputStream:通过readObject方法从输入流中读取字节序列,并反序列化一个对象
try { ObjectInputStream input=new ObjectInputStream(new FileInputStream("oppo.txt")); Object o = input.readObject() }catch (Exception e){ }
3、实现Sericalizable接口,实现Sericalizable接口的时候还要写一个SericalizableUID(火眼质量代码扫描可能会不通过),这个是版本号,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。如果实现接口的时候,没有给定UID,就会使用默认的UID,当使用默认的UID的时候,jvm每次编译的时候会生成一个UID,当后面程序改了一些代码,再次编译的时候会生成不同的UID,会导致反序列化失败!所以在实现Sericalizable接口的时候,我们自己给定一个固定的UID值,这样就能保证编译完再 反序列化的时候的版本一致性。所以能不能成功反序列化,就是看对象中的UID和实体中UID是否一致。
4、实现Externalnalizable接口,在类中实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法(序列化的细节需要由开发人员自己实现,与是否被transient修饰无关),在方法中定义类对象自定义的序列化和反序列化操作。这样通过对象输出流和对象输入流的输入输出方法序列化和反序列化对象时会自动调用类中定义的readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。
注:
1)JDK中除了提供 Serializable 序列化接口外,还提供了另一个序列化接口Externalizable,使用该接口之后,之前基于Serializable接口的序列化机制就将失效。这是因为源码中Externalizable 接口继承了 Serializable 接口。并定义了两个方法 writeExternal 和 readExternal 方法,因此Externalizable 的序列化机制优先级要高于 Serializable。
2)使用 Externalizable 进行序列化时,必须要有默认的构造方法,而Serializable可以没有默认的构造方法。
PB序列化是指将Protocol Buffer(简称PB)数据结构转换为字节流的过程。PB是Google开发的一种高效、可扩展、平台无关的数据交换格式,常用于RPC协议、数据存储和数据交换等领域。
PB官方git:https://github.com/protocolbuffers/protobuf
syntax = "proto3"; message UserInfo { string name = 1; int32 age = 2; repeated string interests = 3; }
通过编译器生成的代码可以使用下面的方式创建和序列化一个UserInfo对象:
UserInfo user = UserInfo.newBuilder().setName("Alice").setAge(30) .addInterests("Programming").addInterests("Reading").build(); byte[] bytes = user.toByteArray();
反序列化的方式类似:
byte[] bytes = ... // 从文件或网络读取字节流 UserInfo user = UserInfo.parseFrom(bytes);
总的来说,PB序列化是一种高效而强大的数据交换方式,适用于需要高性能、高可扩展性,并且对数据体积有要求的场景。
@Tag 是 Protocol Buffers 中的一个注解,用于指定一个字段的标签号(tag),该标签号必须是一个正整数。在序列化和反序列化中,每个字段都需要标签号来标记该字段的类型和位置,只有使用 @Tag 才能保证序列化和反序列化时字段的匹配性和正确性。如果没有使用 @Tag,则默认使用该字段在代码中的位置作为 tag,在代码修改后可能会导致 tag 发生改变,从而导致序列化和反序列化出错。因此,使用 @Tag 是为了保证数据的稳定性和一致性。
遗留:
如何实现节省空间?
各类json的选型?
使用场景?dubbo默认hessian,被替换的原因?
JDK11版本无法反序列化问题?调活动RPC问题?
Apache Avro是一个数据序列化系统
Avro依赖于模式(Schema)。通过模式定义各种数据结构,只有确定了模式才能对数据进行解释,所以在数据的序列化和反序列化之前,必须先确定模式的结构。
Avro作为RPC框架来使用。客户端希望同服务器端交互时,就需要交换双方通信的协议,它类似于模式,需要双方来定义,在Avro中被称为消息(Message)。通信双方都必须保持这种协议,以便于解析从对方发送过来的数据,这也就是握手阶段。
全名:JavaScript Object Notation
户籍:Json是一种轻量级数据交换格式,它采用的是完全独立于编程语言之外的文本格式,同时它也使用了类似c家族的习惯,这些特性使得json成为最理想的数据交换语言。
特点:
1)JSON文本格式的本质就是具有特定格式的字符串
2)JSON比XML有效性更高
JSON对象和JSON数组
示例:
String json1 = "{"id":1,"name":"Tom"}";
String json2 = "[12,"abc",{"id":1,"name":"Tom"}]";
Json对象:
结构:{key1:value1,key2:value2}
格式描述:在键值对与键值对之间用“,”隔开,在键与值之间用:隔开
key的数据类型:字符串
value的数据类型:字符串,数值,JSON对象,JSON数组
Json数组:
结构:[value1,value2,value3]
value的数据类型:字符串,数值,JSON对象,JSON数组
注:JSON的对象和数组可以作为Json对象数组的value数据类型
Json对象对应的是Java中的对象
Json数组对应的是Java中的List集合
JSON不管是在Web开发还是服务器开发中是相当常见的数据传输格式,一般情况我们对于JSON解析构造的性能并不需要过于关心,除非是在性能要求比较高的系统。
四个JSON类库分别为:Gson,FastJson,Jackson,Json-lib。
简单介绍下四个类库的身份背景。
1)Gson(项目地址:https://github.com/google/gson)。
Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。
Gson gson = new Gson(); Object object = gson.fromJson(json, Object.class);//json对象->java对象 List
注:gson可能会导致cpu飙高的情况
2)FastJson(项目地址:https://github.com/alibaba/fastjson)。Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。无依赖,不需要例外额外的jar,能够直接跑在JDK上。FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。FastJson采用独创的算法,将解析的速度提升到极致,超过所有json库。
源码阅读博客:Fastjson源码阅读(一):前言_fastjson源码解析-CSDN博客
使用:利用@JSONField注解
String json = JSON.toJSONString(Object object);//java对象->json对象 Object object = JSON.parseObject(json);//json对象->java对象
注意事项:当对象的某个成员变量为null时,序列化时不会创建相关字段;要用相关的封装类来修改基础数据类型变量
3)Jackson(项目地址:https://github.com/FasterXML/jackson)。相比json-lib框架,Jackson所依赖的jar包较少,简单易用并且性能也要相对高些。而且Jackson社区相对比较活跃,更新速度也比较快。Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式。
4)Json-lib(项目地址:Maven - Json-lib::Welcome)。json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,包括commons-beanutils.jar,commons-collections-3.2.jar,commons-lang-2.6.jar,commons-logging-1.1.1.jar,ezmorph-1.0.6.jar,对于复杂类型的转换,json-lib对于json转换成bean还有缺陷,比如一个类里面会出现另一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。json-lib在功能和性能上面都不能满足现在互联网化的需求。
5)选择一个合适的JSON库要从多个方面进行考虑:字符串解析成JSON性能、字符串解析成JavaBean性能、JavaBean构造JSON性能、集合构造JSON性能、易用性
使用选择原则:
官方地址:Hessian 2.0 Serialization Protocol
参考官方文档的描述: