ObjectInputStream 严格按类中 serialPersistentFields 数组声明的字段名、类型和顺序读取数据,跳过默认序列化逻辑;需配套重写 readObject 方法并调用 defaultReadObject(),否则抛 InvalidClassException。

ObjectInputStream 本身不“实现”serialPersistentFields,而是与 ObjectOutputStream 配合,按类中声明的 serialPersistentFields 数组约定来读取字段 —— 它严格遵循该静态字段定义的字段名、类型和顺序,跳过默认序列化逻辑(如反射遍历所有非 transient 字段)。
serialPersistentFields 是写给序列化机制看的“字段清单”
这个 private static final ObjectStreamField[] serialPersistentFields 不是给开发者调用的 API,而是 JVM 序列化框架(ObjectOutputStream/ObjectInputStream)在运行时主动检查并遵守的契约。只要类里显式定义了它,序列化/反序列化就不再依赖字段声明顺序或是否被 transient 修饰,而是完全以该数组为准。
ObjectInputStream 如何使用它
当 ObjectInputStream 读取一个对象时:
- 先定位到目标类的
serialPersistentFields数组(如果存在) - 按数组中每个
ObjectStreamField的name和type,依次从流中读取对应类型的值(例如readInt()、readObject()、readUTF()等) - 将读出的值,通过
Unsafe或私有字段赋值方式,直接设入对应名称的字段(即使字段是 private 或 final) - 不会读取未在该数组中声明的字段,也不会跳过已声明但当前值为 null 的字段
配套要求:必须重写 writeObject/readObject
仅声明 serialPersistentFields 不够,还必须提供自定义的 writeObject 和 readObject 方法,否则运行时会抛 InvalidClassException(提示 “no valid constructor” 或 “no matching fields”)。这两个方法里要严格按 serialPersistentFields 的顺序调用 ObjectOutputStream.putFields() / ObjectInputStream.readFields(),或者更常见的是直接用 defaultWriteObject()/defaultReadObject() —— 它们内部会自动识别并遵从 serialPersistentFields。
立即学习“Java免费学习笔记(深入)”;
例如:
private void writeObject(ObjectOutputStream s) throws IOException {s.defaultWriteObject(); // 自动按 serialPersistentFields 写
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject(); // 自动按 serialPersistentFields 读
}
注意字段顺序和类型必须完全匹配
数组中字段的声明顺序,就是流中数据的物理顺序。如果 serialPersistentFields 写成 {new ObjectStreamField("id", int.class), new ObjectStreamField("name", String.class)},那么 ObjectInputStream 就先读一个 int,再读一个 String。若实际流中顺序错位、类型不符(比如本该读 int 却遇到字符串),就会抛 StreamCorruptedException 或 ClassNotFoundException。


















