@toc:
- 序列化 Example
- Serializable 接口和 serialVersionUID
- 类的哪些字段不会被序列化
- 如何自定义序列化的策略?ArrayList 是如何序列化数组的?
- JDK 序列化的实现
序列化 Example
class User implements java.io.Serializable { |
Serializable 接口和 serialVersionUID
类必须实现自 Serializable 接口,才可以被 ObjectOutputStream & ObjectInputStream 序列化和反序列化,序列化时如果遇到未实现 Serializable 接口的类,会抛出 NotSerializableException 异常;
建议:可序列化的类定义自己的 serialVersionUID:
private static final long serialVersionUID
,在进行兼容升级时保持不变,也可以通过改变序列化 ID 限制某些用户使用;在序列化时,VersionUID 被写入类对象的字节流,在反序列化时,ObjectInputStream 读取类对象字节流,并比较反序列化对象的 VersionUID 跟本地 class 的 VersionUID 作比较,如果不一致则抛出 InvalidClassException 异常;
如果没有定义 serialVersionUID,ObjectStreamClass(序列化 & 反序列化操作的对象) 会自动生成一个,生成规则根据类名,接口名,属性名, 以及描述符等生成一个64位的哈希数字(见
ObjectStreamClass.getSerialVersionUID()
方法),每次改动类的代码都会导致自动生成的 serialVersionUID 发生变化;
类的哪些字段不会被序列化
- static 成员
- 被声明为 transient 的成员
- 如果一个类有父类,那么父类中的成员如果也需要可序列化,那么父类也要实现 Serializable 接口
如何自定义序列化策略
如何自定义序列化策略?
- 在序列化的类中实现
writeObject(ObjectOutputStream)
和readObject(ObjectInputStream)
方法即可
ArrayList 是如何序列化数组的?
- ArrayList 内部是数组实现的,数据保存在
elementData[]
,但实际使用中数组的大部分位置都是空值,为了让空元素不会被序列化,ArrayList 把elementData[]
声明为 transient,并实现了 writeObject & readObject 方法
JDK 序列化的实现
如果一个类中包含 writeObject 和 readObject 方法,那么这两个方法是怎么被调用的?
Serializable 只是一个空接口,它是如何保证只有实现类才可以被序列化呢?
以 ObjectOutputStream 序列化为例,调用栈如下:
ObjectOutputStream.writeObject |