Java对象的序列化与反序列化
两个进程远程通信时,无论发送什么类型的数据,网络上走的都是二进制序列。发送方要把 Java 对象变成字节序列,接收方再把字节序列恢复成对象。
把 Java 对象转换为字节序列叫做序列化;把字节序列恢复为 Java 对象叫做反序列化。常见用途有两个:把对象的字节序列永久存到磁盘(通常是一个文件);在网络上传送对象。
| 接口 | 谁控制过程 | 反序列化时 |
|---|---|---|
| Serializable | 默认机制;可自定义 writeObject / readObject | 不调用构造方法 |
| Externalizable | 类自己实现 writeExternal / readExternal | 先调用 public 无参构造 |
一、JDK 类库中的序列化 API
java.io.ObjectOutputStream 是对象输出流,writeObject(Object obj) 把指定对象序列化并写入目标流。java.io.ObjectInputStream 是对象输入流,readObject() 从输入流读字节序列并还原为对象。
只有实现了 Serializable 或 Externalizable 的类,其对象才能被序列化。Externalizable 继承自 Serializable:实现它的类完全自己控制序列化行为;只实现 Serializable 的类走默认方式。
序列化步骤:创建对象输出流(可包装文件输出流等),再调用 writeObject()。反序列化:创建对象输入流,再调用 readObject()。写入和读取的顺序必须一致。
输出类似:obj1=你好!;obj2=某个 Date;obj3=name=阿蜜果, age=24;obj4=123。
二、实现 Serializable 接口
ObjectOutputStream 只能序列化实现了 Serializable 的对象。默认方式只序列化非 transient 的实例变量,不序列化 transient 字段,也不序列化静态变量。
按默认方式反序列化时:若内存里该类尚未加载,会先加载并初始化;classpath 里没有对应 class 文件则抛 ClassNotFoundException。反序列化不会调用类的任何构造方法。
若要自己控制过程,可提供下面两个私有方法。对象有 writeObject 时就会走它,否则走默认。方法里可以先调 defaultWriteObject() 做默认序列化,再补自己的逻辑;反序列化对应 defaultReadObject()。
对象里若有敏感信息,按默认方式序列化后在网络上传输可能被截获,可以先加密再写入,读回来再解密。默认序列化会递归遍历整个对象图,图很复杂时又占空间又耗时。把不需要持久化的成员标成 transient,能缩小体积、提高性能。
三、实现 Externalizable 接口
Externalizable 继承 Serializable。实现它之后,序列化行为完全由这个类自己负责。接口声明两个方法:前者负责写,后者负责读。
反序列化实现了 Externalizable 的对象时,会先调用类的public 无参构造方法,这和 Serializable 的默认方式不同。若删除无参构造,或把它改成 private、默认、protected,会抛出 java.io.InvalidClassException: no valid constructor。
一句话总结:Serializable 走默认(可加 transient / 自定义读写),Externalizable 完全自己写;两者都是为了把对象变成字节再还原回来。
转载请注明来源:Java对象的序列化与反序列化







