1、什么是序列化
- 序列化:将对象写入到IO流中
- 反序列化:从IO流中恢复对象
补充:
- Serializable 是一个空接口,它的目的仅是标识一个类的对象可以被序列化。
- Java 提供的一种高效机制:将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其当前状态写入到临时存储区或持久性存储区,之后,便可以通过从存储区中读取或反序列化对象的状态信息,来重新创建该对象。
2、什么情况下需要序列化
- 当你想把的内存中的对象持久化时(如写硬盘、数据库系统等)
- 当你想用套接字在网络上传送对象时(如 MR shuffle)
- 当你想通过RMI传输对象的时(如 RPC 远程调用)
特别注意:在分布式应用中,必须实现序列化,因为某个节点的内存不够用时,程序就要将内存里面的一部分对象暂时地保存到硬盘中。
3、什么情况下不需要序列化
并非所有的对象都可以序列化,比如:
- 安全方面的原因,比如一个对象拥有 private,public 等 field,对于一个要传输的对象,比如写到文件,或者进行 rmi 传输 等等,在序列化进行传输的过程中,这个对象的 private 等域是不受保护的。
- 资源分配方面的原因,比如 socket,thread 类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。
注意:如果想让某个变量不被序列化,使用transient修饰
4、实现序列化的步骤
- extends Serializable ( Scala 中 )或者 implements Serializable (Java 中)
- 生成 serialVersionUID
5、相关注意事项
- 所有需要网络传输的对象都需要实现序列化接口,建议所有的javaBean都实现Serializable接口。
- 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
- 如果想让某个变量不被序列化,使用transient修饰。
- 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
- 反序列化时必须有序列化对象的class文件。
- 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
- 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
- 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
- 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。
参考
https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html?is-external=true