1、什么是序列化

 

  •    序列化:将对象写入到IO流中
  •    反序列化:从IO流中恢复对象

   
  补充:

  •    Serializable 是一个空接口,它的目的仅是标识一个类的对象可以被序列化。
  •    Java 提供的一种高效机制:将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其当前状态写入到临时存储区或持久性存储区,之后,便可以通过从存储区中读取或反序列化对象的状态信息,来重新创建该对象。

2、什么情况下需要序列化

 

  •    当你想把的内存中的对象持久化时(如写硬盘、数据库系统等)
  •    当你想用套接字在网络上传送对象时(如 MR shuffle)
  •    当你想通过RMI传输对象的时(如 RPC 远程调用)

特别注意:在分布式应用中,必须实现序列化,因为某个节点的内存不够用时,程序就要将内存里面的一部分对象暂时地保存到硬盘中。

3、什么情况下不需要序列化

并非所有的对象都可以序列化,比如:

  •     安全方面的原因,比如一个对象拥有 private,public 等 field,对于一个要传输的对象,比如写到文件,或者进行 rmi 传输  等等,在序列化进行传输的过程中,这个对象的 private 等域是不受保护的。
  •     资源分配方面的原因,比如 socket,thread 类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。

注意:如果想让某个变量不被序列化,使用transient修饰

private transient String address;

4、实现序列化的步骤

 

  1. extends Serializable ( Scala 中 )或者 implements Serializable (Java 中)
  2. 生成 serialVersionUID
// 方式一:默认的1L
private static final long serialVersionUID = 1L;

// 方式二:根据类名、接口名、成员方法及属性等来生成一个 64 位的哈希值
private static final long serialVersionUID = xxxxL;

5、相关注意事项

 

  •     所有需要网络传输的对象都需要实现序列化接口,建议所有的javaBean都实现Serializable接口。
  •     对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
  •     如果想让某个变量不被序列化,使用transient修饰。
  •     序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
  •     反序列化时必须有序列化对象的class文件。
  •     当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
  •     单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
  •     同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
  •     建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。   
     

参考

​https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html?is-external=true​