Java序列化以及反序列化

1. 什么是序列化和反序列化

  • 序列化:将对象状态转化为可保持或者传输的字节序列的过程称为序列化
  • 反序列化:将字节序列恢复为对象的的过程称为饭序列化
  • 两个过程配合起来能够完成内存中对象的传输和保存

2. 什么时候需要序列化和反序列化

当我们只在本地JVM里运行下Java实例, 这个时候是不需要什么序列化和反序列化的, 但当我们需要将内存中的对象持久化到磁盘, 数据库中时, 当我们需要与浏览器进行交互时, 当我们需要实现RPC时, 这个时候就需要序列化和反序列化了

总结:当我们需要保存内存中的对象或者在网络上传输内存中对象的时候就需要序列化技术

3. 为啥要序列化的对象都需要实现

在Java中实现了Serializable接口后, JVM会在底层帮我们实现序列化和反序列化, 如果我们不实现Serializable接口, 那自己去写一套序列化和反序列化代码

4. 为啥需要设置SerializableVersionUID

如果不显示指定serialVersionUID, JVM在序列化时会根据属性自动生成一个serialVersionUID, 然后与属性一起序列化, 再进行持久化或网络传输. 在反序列化时, JVM会再根据属性自动生成一个新版serialVersionUID, 然后将这个新版serialVersionUID与序列化时生成的旧版serialVersionUID进行比较, 如果相同则反序列化成功, 否则报错.
如果显示指定了serialVersionUID, JVM在序列化和反序列化时仍然都会生成一个serialVersionUID, 但值为我们显示指定的值, 这样在反序列化时新旧版本的serialVersionUID就一致了.
在实际开发中, 不显示指定serialVersionUID的情况会导致什么问题? 如果我们的类写完后不再修改, 那当然不会有问题, 但这在实际开发中是不可能的, 我们的类会不断迭代, 一旦类被修改了, 那旧对象反序列化就会报错. 所以在实际开发中, 我们都会显示指定一个serialVersionUID, 值是多少无所谓, 只要不变就行

5. 目前有哪几种序列化方式,以及性能对比

5.1 Java原生序列化

只要让类实现 Serializable接口就行,序列化具体的实现是由ObjectOutputStream和ObjectInputStream来实现的
缺点:

1:序列化码流太大
2:序列化效率低
3:无法跨语言
优点:
1: 简单

5.2 JSON序列化

JSON 可能是我们最熟悉的一种序列化格式了,JSON 是典型的 Key-Value 方式,没有数据类型,是一种文本型序列化框架,JSON 的具体格式和特性,网上相关的资料非常多,这里就不再介绍了。他在应用上还是很广泛的,无论是前台 Web 用 Ajax 调用、用磁盘存储文本类型的数据,还是基于 HTTP 协议的 RPC 框架通信,都会选择 JSON 格式。
缺点:
1:JSON进行序列化的额外空间开销比较大,对于大数据量服务就意味着需要巨大的内存和磁盘开销
2:JSON没有类型,但像Java这种强类型语言,需要通过反射统一解决,所以性能不会太好
优点:
1:简洁明了

5.3 Hessian

Hessian 是动态类型、二进制、紧凑的,并且可跨语言移植的一种序列化框架。Hessian 协议要比 JDK、JSON 更加紧凑,性能上要比 JDK、JSON 序列化高效很多,而且生成的字节数也更小

Student student = new Student(); 
student.setNo(101);  
student.setName("HESSIAN"); 
//把student对象转化为byte数组
ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
Hessian2Output output = new Hessian2Output(bos); 
output.writeObject(student); 
output.flushBuffer(); 
byte[] data = bos.toByteArray(); 
bos.close(); 
//把刚才序列化出来的byte数组转化为student对象
ByteArrayInputStream bis = new ByteArrayInputStream(data); 
Hessian2Input input = new Hessian2Input(bis); 
Student deStudent = (Student) input.readObject(); 
input.close(); 
System.out.println(deStudent);

缺点:
1:官方版本对Java里面一些常见对象的类型不支持,
比如LinkedHashMap、LinkedHashSet 等,但是可以通过扩展CollectionDeserializer 类修复,
Locale 类,可以通过扩展 ContextSerializerFactory 类修复;
Byte/Short 反序列化的时候变成 Integer
优点:
1:相对于JDk,JSON,更加高效,生成的字节数更小
2:有非常好的兼容性和稳定性

5.4 Protobuf

Protobuf 是 Google 公司内部的混合语言数据标准,是一种轻便、高效的结构化数据存储格式,可以用于结构化数据序列化,支持 Java、Python、C++、Go 等语言。Protobuf使用的时候需要定义 IDL(Interface description language),然后使用不同语言的 IDL编译器,生成序列化工具类
缺点:
1:为了提高性能,protobuf采用了二进制格式进行编码。这直接导致了可读性差
2:对于具有反射和动态语言来讲,用起来比较费劲
优点:
1:高效
2:支持多种语言
3:支持向前,向后兼容

5.5 Thirft

Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能,并提供多种服务器工作模式,用户通过Thrift的IDL(接口定义语言)来描述接口函数及数据类型,然后通过Thrift的编译环境生成各种语言类型的接口文件,用户可以根据自己的需要采用不同的语言开发客户端代码和服务器端代码。
缺点:
1:没有官方文档
2:Thrift序列化二进制不可读,调试困难
3:buf fix 和更新不积极,维护成本过高
4:RPC 在 0.6.1 升级到 0.7.0 是不兼容的
优点:
1:特性丰富
2:性能不错
3:有很多开源项目的周边支持 都是 thrift

你可能感兴趣的:(前后端,序列化)