objectstreamfield是描述序列化字段的元信息载体,不直接控制行为;真正起作用的是serialpersistentfields数组声明或writeobject/readobject中putfield的使用,其字段名、类型、顺序必须与类严格一致,否则导致静默反序列化失败。

ObjectStreamField 不是用来“自定义变量字段”的工具类,它本身不控制字段行为,而是**描述序列化字段的元信息**。真正起控制作用的是你如何声明 serialPersistentFields 数组,或如何在 writeObject/readObject 中使用 PutField。它的字段名、类型、顺序必须与类中实际字段严格一致,否则反序列化会静默失败——比如字段值为 null 或 0,却无任何异常提示。
serialPersistentFields 是唯一主动声明方式
这是最常用也最明确的控制入口。你需要在类中声明一个静态 final 数组:
- 数组元素是
ObjectStreamField实例,但不能手动 new —— JVM 在读取该数组时自动构建 - 每个元素的
name必须和类中字段名完全相同(区分大小写),type必须是对应字段的精确 Class 对象 - 数组顺序决定字节流中字段的排列顺序,也决定反序列化时的读取顺序
- 只列出你想参与序列化的字段;没列的字段(包括非 transient 的)将被跳过
字段名或类型不匹配会导致静默错位
这不是运行时报错的问题,而是协议层逻辑错位:
- 比如类中字段叫
userId,但数组里写成"userID"→ 反序列化时该字段永远得不到值 - 字段类型写成
Integer.class,而实际是int→ 类型不匹配,JVM 可能填入默认值0并继续执行 - 数组里多写了一个类中不存在的字段名 → 反序列化时直接跳过,不报错也不警告
配合 writeObject/readObject 实现动态控制
当你需要更灵活的行为(如按条件序列化、转换值、兼容旧版本),就重写这两个方法:
- 在
writeObject中调用out.putFields()获取PutField,再用put("name", value)写入字段 - 在
readObject中调用in.readFields()获取GetField,再用get("name", defaultValue)读取 - 此时
ObjectStreamField不出现于代码中,但它隐含在PutField/GetField的字段契约里 - 这种方式允许你在读写过程中做校验、默认值填充、类型适配等操作
别碰 unshared 和 offset 这些底层字段
isUnshared()、getOffset()、setOffset() 属于 JVM 内部机制使用的属性:
-
unshared参数仅在构造ObjectStreamField时有意义,用于指定该字段是否以writeUnshared方式处理(即禁止对象图共享) -
offset是字段在对象内存布局中的偏移量,由 JVM 在运行时计算,手动设置无效且危险 - 日常开发中几乎不需要关注这些,除非你在写序列化框架或调试极端兼容问题











