Java中ObjectInputStream和ObjectOutputStream可直接读写枚举,因其自动实现Serializable且JVM保障单例性;序列化仅保存枚举常量名称,反序列化通过Enum.valueOf查找实例,自定义字段和ordinal不参与序列化。

Java 中 ObjectInputStream 和 ObjectOutputStream 可以直接读写枚举(enum)类型,**无需额外实现 Serializable 接口或自定义序列化逻辑**——因为枚举类在编译时自动继承 java.lang.Enum,而 Enum 本身已实现 Serializable,且 JVM 对枚举序列化有特殊保障机制。
枚举的序列化本质是写入枚举常量名称
Java 序列化枚举时,不会保存字段值或构造参数,而是只保存其声明时的**枚举常量名称(name)**。反序列化时,JVM 通过该名称调用 Enum.valueOf(Class, String) 查找对应实例,确保单例性和类型安全。
- 即使枚举含自定义字段(如
private final int code;),这些字段不会被序列化;反序列化后得到的是原枚举类中同名的静态实例,其字段值来自源码定义,而非流中数据 - 枚举的
ordinal()值不参与序列化,重排序枚举常量(如把RED移到第二位)不影响反序列化结果,只要名称不变 - 若反序列化时找不到同名常量(如类版本升级删了某个枚举值),会抛出
InvalidObjectException
基本读写操作示例
只需确保枚举类和使用它的类都可被序列化(枚举默认满足),即可用标准对象流处理:
// 定义枚举
public enum Color {
RED(1), GREEN(2), BLUE(3);
private final int code;
Color(int code) { this.code = code; }
public int getCode() { return code; }
}
写入:
立即学习“Java免费学习笔记(深入)”;
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("color.ser"))) {
oos.writeObject(Color.RED); // 写入枚举实例
}
读取:
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("color.ser"))) {
Color c = (Color) ois.readObject(); // 直接强制转型,类型安全
System.out.println(c + ", code=" + c.getCode()); // 输出:RED, code=1
}
注意反序列化时的类路径与版本兼容性
枚举反序列化依赖运行时类定义,需保证:
- 读取方 classpath 中存在同包同名的枚举类,且至少包含待反序列化的常量
- 如果枚举类被重构(如改名、删常量),旧序列化数据无法加载,会抛异常;新增常量不影响旧数据读取
- 不建议在枚举中添加非 transient 非 static 的可变字段,因其状态不会被序列化,易引发误解
替代方案:显式控制名称/值序列化(按需)
若业务需要保存枚举的自定义属性(如 code)或兼容不同语言/系统,可避免直接序列化枚举实例,转而序列化其名称或编码:
- 写入时:用
enum.name()或enum.ordinal()写字符串/整数 - 读取时:用
Enum.valueOf(Class, name)或values()[ordinal]恢复实例 - 更健壮的做法是定义公共 API 方法,如
toCode()/fromCode(int),解耦序列化逻辑


















