⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 小哈学Java 「犬小哈」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

先给结论

序列化 = 把 Java 对象变成字节流(方便存储或网络传输)。反序列化 = 反过来,字节流变回对象。

实现方式:让类 implements Serializable。但说句直白的——除非维护老代码,否则别用 Java 原生序列化。性能差、体积大、安全漏洞一堆。新项目用 JSON(Jackson/Gson)或 Protobuf。

三个核心概念

  • Serializable 接口:标记接口,没有任何方法。作用就是告诉 JVM:”这个类的对象允许被序列化”。不实现它,序列化时直接抛 NotSerializableException。

  • serialVersionUID:类的”版本指纹”。反序列化时 JVM 会比对字节流中的 UID 和当前类的 UID,不一致直接抛 InvalidClassException。必须显式声明——编译器自动生成的 UID 会因为加个方法就变掉,导致莫名其妙的反序列化失败。

  • transient 关键字:修饰的字段在序列化时被跳过。典型用途:密码、数据库连接、不可序列化的对象引用。反序列化后这些字段是默认值(null、0、false)。

代码:序列化一把梭

// 1. 实现 Serializable
publicclass User implements Serializable {
privatestaticfinallong serialVersionUID = 1L; // 2. 显式声明
private String name;
privateint age;
privatetransient String password; // 3. 敏感字段不序列化

// 构造方法、getter、setter 省略
}

// 序列化 & 反序列化
publicclass SerializationDemo {
public static void main(String[] args) throws Exception {
User user = new User("Alice", 30, "secret");

// 写入文件
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("user.dat"))) {
oos.writeObject(user);
}

// 从文件还原
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("user.dat"))) {
User restored = (User) ois.readObject();
System.out.println(restored.getName()); // Alice
System.out.println(restored.getPassword()); // null(transient 的代价)
}
}
}

Java 原生序列化 vs 现代方案

方案 优势 劣势 适用场景
Java 原生 JVM 深度集成,用起来简单 体积大、性能差、存在远程代码执行漏洞 老系统兼容
JSON(Jackson/Gson) 人类可读,跨语言,生态好 文本格式效率低,不支持循环引用 Web API,配置文件
Protobuf / Thrift / Avro 高性能二进制,体积小,有 Schema 需要额外定义 .proto 文件 RPC 框架(gRPC),大数据系统

结论很明确:Java 原生序列化是历史产物。新项目 Web 场景用 JSON,高性能 / 跨语言场景用 Protobuf。

踩坑清单

  1. 必须显式声明 serialVersionUID——这是防止反序列化翻车的第一道防线
  2. transient 字段反序列化后是默认值——如果业务依赖这些字段,需要在 readObject() 中手动恢复
  3. 永远不要反序列化不可信来源的数据——Java 反序列化漏洞(如 Apache Commons Collections 利用链)是真实的安全威胁。JDK 9+ 可用 ObjectInputFilter 做白名单过滤
  4. 别序列化整个大对象图——只传必要的数据,否则体积和性能都会爆
文章目录
  1. 1. 先给结论
  2. 2. 三个核心概念
  3. 3. 代码:序列化一把梭
  4. 4. Java 原生序列化 vs 现代方案
  5. 5. 踩坑清单