子类单独实现Serializable时,父类字段不参与序列化,反序列化后被重置为默认值;需通过自定义writeObject/readObject方法显式处理父类字段。

父类没实现 Serializable,子类单独实现时,反序列化后父类字段不会恢复原始值,而是被重置为 Java 类型默认值——这不是“丢失”,而是根本没写入字节流。
父类字段不参与序列化的硬性规则
Java 序列化只处理显式声明 implements Serializable 的类所定义的实例字段。继承链中只要某一级父类未实现该接口,它声明的所有字段(包括泛型字段如 ID id)都会被跳过:
- 不写入输出流(
ObjectOutputStream) - 不在反序列化时从输入流(
ObjectInputStream)中读取 - 子类字段照常保存和恢复,但父类部分状态完全清零
反序列化时父类字段的默认值表现
反序列化过程中,JVM 会调用父类的无参构造器重建父类部分。此时所有父类字段按类型赋予初始默认值:
- 引用类型(如
String、ID、自定义对象)→ null - 数值类型(
int、long、double等)→ 0 或 0.0 - 布尔类型(
boolean)→ false - 字符类型(
char)→ '\u0000'
注意:这个过程与子类构造时是否给父类字段赋过值无关。哪怕 new User(1L, "a", "b") 显式设置了 id,反序列化后 getId() 仍返回 null。
立即学习“Java免费学习笔记(深入)”;
反序列化能否成功,取决于父类是否有可访问无参构造器
没有无参构造器,反序列化直接失败;有且可访问,才能完成重建并填入默认值:
- 父类含
public Parent() {}→ 反序列化成功,字段为默认值 - 父类只有
public Parent(String id) {},无无参构造 → 抛InvalidClassException: no valid constructor - 父类无参构造是
private或protected(且子类不在同一包内)→ 同样失败
如何让父类字段在反序列化后不为默认值
必须绕过 JVM 默认重建逻辑,由子类主动接管父类字段的读写:
- 在子类中定义
private void writeObject(ObjectOutputStream out),先调用defaultWriteObject(),再用out.writeLong()等显式写出父类字段 - 对应定义
private void readObject(ObjectInputStream in),先调用defaultReadObject(),再用in.readLong()等读回并赋值给父类字段(需通过反射或 setter) - 前提是父类字段可访问,或提供 public/protected setter,且父类有无参构造器供 initial 构建


















