serializable是标记接口,无方法,仅由jvm通过instanceof检查起作用;真正序列化逻辑由jvm内置机制和反射实现,需注意serialversionuid兼容性、transient字段跳过、成员变量可序列化等关键事项。

Java 中实现 Serializable 接口非常简单,但它只是“标记接口”,不包含任何方法。真正起作用的是 JVM 在序列化/反序列化时对它的识别。关键在于理解它怎么用、有什么注意事项,而不是“实现”逻辑本身。
1. 基本写法:加个空接口就行
只需让类 implements Serializable,并通常建议显式定义一个 serialVersionUID 字段:
import java.io.Serializable;
<p>public class User implements Serializable {
private static final long serialVersionUID = 1L; // 推荐手动指定</p><pre class="brush:java;toolbar:false;">private String name;
private int age;
private transient String password; // 不参与序列化}
注意:
- serialVersionUID 是序列化版本号,用于反序列化时校验类结构是否兼容;不写会由 JVM 自动生成(但容易因编译器或类变更而变化),导致 InvalidClassException。
- transient 修饰的字段不会被序列化,比如敏感信息或临时状态。
2. 序列化和反序列化的典型操作
要用 ObjectOutputStream 和 ObjectInputStream 配合文件或字节流:
- 序列化(保存对象):
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) { oos.writeObject(new User("Alice", 25)); } - 反序列化(恢复对象):
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) { User user = (User) ois.readObject(); }
注意:两个操作都必须捕获或声明 IOException 和 ClassNotFoundException(反序列化时类型找不到)。
3. 处理不可序列化的字段或自定义过程
如果类里有不能序列化的成员(如线程、Socket、数据库连接等),除了用 transient,还可以通过以下方式控制:
- 提供
private void writeObject(ObjectOutputStream out)和private void readObject(ObjectInputStream in)方法,手动指定序列化逻辑。 - 实现
Externalizable接口(继承自Serializable),完全接管序列化过程(需重写writeExternal和readExternal)。 - 确保所有非
transient的引用类型字段所属的类也实现了Serializable,否则会抛NotSerializableException。
4. 实际开发中的常见坑
看似简单,但容易踩雷:
- 父类没实现
Serializable,子类实现了 → 子类可序列化,但父类字段不会被保存(除非父类也序列化或提供无参构造)。 - 使用 Lombok 的
@Data或@RequiredArgsConstructor时,记得加上@Serial(Lombok 1.18.30+)或手动加serialVersionUID和implements Serializable。 - 集合类(如
ArrayList、HashMap)本身已实现Serializable,但要求其元素类型也必须可序列化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











