温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java序列化如何工作

发布时间:2026-07-24 09:43:25 来源:亿速云 阅读:101 作者:小樊 栏目:编程语言

Java 序列化(Serialization) 是指把对象转换为字节流的过程,便于持久化存储或网络传输;**反序列化(Deserialization)**则是把字节流恢复为对象。

下面从原理、流程、关键机制、示例、注意事项几个方面系统说明。


一、Java 序列化的基本原理

Java 序列化依赖两个核心接口:

  • java.io.Serializable(标记接口,无方法)
  • java.io.Externalizable(可自定义序列化过程)

最常见的是 Serializable。

核心类

  • ObjectOutputStream:序列化(对象 → 字节流)
  • ObjectInputStream:反序列化(字节流 → 对象)

二、Serializable 的工作流程

1️⃣ 对象序列化流程

ObjectOutputStream oos = new ObjectOutputStream(outputStream);
oos.writeObject(obj);

JVM 做了什么?

  1. 检查对象是否实现 Serializable
    • 没有 → 抛 NotSerializableException
  2. 写入序列化描述信息
    • 类名
    • serialVersionUID
    • 字段类型、签名等
  3. 递归序列化对象
    • 对象中的非 transient、非 static 字段
    • 引用的其他对象也会被序列化(形成对象图)
  4. 写入字段值
  5. 结束标记

2️⃣ 对象反序列化流程

ObjectInputStream ois = new ObjectInputStream(inputStream);
Object obj = ois.readObject();

JVM 做了什么?

  1. 读取字节流
  2. 根据类名加载 Class
  3. 匹配 serialVersionUID
  4. 分配对象内存(不调用构造方法)
  5. 恢复字段值
  6. 如果有 readResolve(),调用它

三、Serializable 示例代码

1️⃣ 定义可序列化对象

import java.io.*;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private transient String password;

    public User(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }

    @Override
    public String toString() {
        return name + ", " + age + ", " + password;
    }
}

2️⃣ 序列化

User user = new User("Tom", 18, "123456");

try (ObjectOutputStream oos =
             new ObjectOutputStream(new FileOutputStream("user.obj"))) {
    oos.writeObject(user);
}

3️⃣ 反序列化

try (ObjectInputStream ois =
             new ObjectInputStream(new FileInputStream("user.obj"))) {
    User user = (User) ois.readObject();
    System.out.println(user);
}

输出:

Tom, 18, null

transient 字段不会被序列化


四、serialVersionUID 的作用(非常重要)

private static final long serialVersionUID = 1L;

作用

用于 版本一致性校验

反序列化时:

  • 如果字节流中的 serialVersionUID
  • 和当前类的 serialVersionUID 不一致
    → 抛 InvalidClassException

两种情况

  • 显式定义:版本可控(推荐)
  • 不定义:JVM 自动生成(复杂、不稳定)

✅ 生产环境必须显式定义


五、transient 和 static 的区别

关键字 是否序列化
transient ❌ 不序列化
static ❌ 不序列化(属于类,不属于对象)

六、自定义序列化(高级)

1️⃣ 使用 writeObject / readObject

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
    oos.writeObject(password); // 手动序列化
}

private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    password = (String) ois.readObject();
}

✅ 用于加密、校验、兼容旧数据


2️⃣ readResolve 单例保护

protected Object readResolve() {
    return INSTANCE;
}

防止反序列化破坏单例。


七、Externalizable(了解)

public interface Externalizable extends Serializable {
    void writeExternal(ObjectOutput out);
    void readExternal(ObjectInput in);
}

特点:

  • 完全手动控制
  • 必须有无参构造器
  • 性能略好,但复杂

八、Java 序列化的缺点

❌ 安全问题(反序列化漏洞)
❌ 性能较差
❌ 字节流不跨语言
❌ 版本兼容性差

因此:

  • 不推荐用于 RPC / 长期存储
  • 现代系统常用:
    • JSON(Jackson / Gson)
    • Protobuf
    • Kryo
    • Hessian

九、总结一句话

Java 序列化通过 Serializable 标记接口,由 ObjectOutputStream / ObjectInputStream 在 JVM 内部将对象转换为字节流并恢复,核心依赖 serialVersionUID 和对象图递归处理,但因其安全性和性能问题,实际生产中应谨慎使用。

如果你愿意,我可以:

  • 画一张 序列化流程图
  • 讲 反序列化漏洞原理
  • 对比 Java 序列化 vs JSON / Protobuf
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手