Java序列化是ObjectOutputStream将对象转为二进制字节流、ObjectInputStream原样重建的过程,要求类实现Serializable接口(空标记接口,用于JVM校验);未实现则抛NotSerializableException,父类未实现时其字段不序列化且需无参构造器;transient、static及非Serializable类型的字段不参与序列化;显式声明serialVersionUID可避免InvalidClassException。

Java序列化与反序列化不是“把对象转成字符串”这种模糊理解,而是明确指:ObjectOutputStream 把内存中活的对象写成二进制字节流,ObjectInputStream 再从字节流里原样重建出对象实例——这个过程要求类必须实现 Serializable 接口,否则直接抛 NotSerializableException。
为什么必须实现 Serializable 接口?
它是个空接口(marker interface),不提供任何方法,纯粹是给 JVM 下的一道“通行令”。JVM 在执行序列化前会检查:该类及其所有非 transient 字段的类型,是否都“持证上岗”。没实现?立刻拒绝,不给机会。
- 不实现就调用
writeObject()→ 立即抛NotSerializableException - 父类没实现
Serializable,子类实现了 → 父类字段不会被序列化,且父类必须有无参构造器(反序列化时用来初始化父类部分) - 接口、抽象类本身不能被序列化,只有具体实现类可以
serialVersionUID 是什么?不写会怎样?
它是类的“版本指纹”,一个 long 类型的静态常量。JVM 用它校验序列化方和反序列化方的类结构是否兼容。
- 显式声明(如
private static final long serialVersionUID = 1L;)→ 版本可控,字段增减、方法改名不影响反序列化 - 不声明 → JVM 自动计算,但只要类结构稍有变动(比如加个字段、改个访问修饰符),生成的值就变 → 反序列化时抛
InvalidClassException - IDE(如 IntelliJ)通常提示“Add ‘serialVersionUID’”,别点“Ignore”
哪些字段不会被序列化?
三个明确排除项:
全诚易惠通优惠折扣信息店铺管理系统是全诚团队继 “全诚商城”“外卖通” 之后又一新概念重量级作品,该系统以收集本地所有店铺优惠折扣信息为核心,在构思、设计、代码处理上都做了严密的部署和检查,继承了全诚系列产品核心模块的基础上进化而来,即为新作品,也系高度成熟度的作品,加之全诚团队精心技术支持,可为用户营造一个长期可靠的系统运行环境。本系统较易惠通相比,业务和经营范围覆盖面积更广更大,可涵盖本地所有
立即学习“Java免费学习笔记(深入)”;
-
transient修饰的字段:比如private transient String password;,反序列化后为null(或默认值) -
static字段:属于类,不属于对象实例,序列化只管“对象状态”,不管“类状态” - 未实现
Serializable的字段类型:比如你有个字段是自定义的Connection类,它没实现接口 → 直接报错,除非标为transient
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private int age;
private transient String token; // 不序列化
private static String version = "1.0"; // 静态字段,不参与序列化
}
真正容易被忽略的,是“父类未实现 Serializable 时,子类反序列化会静默调用父类无参构造器”——这意味着父类字段会被重置为默认值,而不是保留原始状态。这点在继承体系复杂时,极易引发数据丢失却难以排查。









