杨斌
发布于 2026-04-16 / 4 阅读
0
0

Java中的序列化和反序列化

Java 中的序列化(Serialization)和反序列化(Deserialization),本质上是:

  • 序列化:把 Java 对象转换成可以存储或传输的字节流

  • 反序列化:把字节流再恢复成 Java 对象


一、为什么需要序列化

Java 对象默认只存在于 JVM 内存中。

比如:

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

这个 user 对象:

  • 程序关闭后就消失

  • 无法直接通过网络发送

  • 无法直接写入文件

所以需要:

对象 → 字节流 → 保存到文件 / 网络传输 / 缓存

二、序列化流程图

Java对象
   ↓
序列化
   ↓
二进制字节流
   ↓
文件 / 网络 / Redis / 数据库

反过来:

二进制字节流
   ↓
反序列化
   ↓
Java对象
image-QMxW.png

三、实现序列化的条件

Java 类必须实现:

Serializable

这是一个标记接口:

public interface Serializable {
}

没有方法,只是告诉 JVM:

👉 这个类可以被序列化


四、示例代码


1. 定义实体类

import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

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

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

2. 序列化对象到文件

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializableTest {
    public static void main(String[] args) throws Exception {
        User user = new User("Tom", 18);

        ObjectOutputStream out =
                new ObjectOutputStream(new FileOutputStream("user.dat"));

        out.writeObject(user);
        out.close();

        System.out.println("对象已序列化");
    }
}

3. 反序列化对象

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class SerializableTest2 {
    public static void main(String[] args) throws Exception {
        ObjectInputStream in =
                new ObjectInputStream(new FileInputStream("user.dat"));

        User user = (User) in.readObject();
        in.close();

        System.out.println(user);
    }
}

输出:

Tom - 18

五、核心类


ObjectOutputStream

用于写对象:

writeObject()

例如:

out.writeObject(user);

ObjectInputStream

用于读对象:

readObject()

例如:

User user = (User) in.readObject();

六、serialVersionUID 的作用

通常建议写:

private static final long serialVersionUID = 1L;

完整写法:

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

为什么需要它?

防止类修改后反序列化失败,相当于类的版本号。

例如:

第一次保存对象时类结构:

name
age

后来修改成:

name
age
email

JVM 会比较版本号:

serialVersionUID

如果不一致,就报错:

InvalidClassException
image-mYAO.png

七、哪些字段不会序列化

1.加 transient

private transient String password;

表示:

👉 此字段不会被序列化

示例:

public class User implements Serializable {
    private String name;
    private transient String password;
}

序列化后:

password == null

2.static修饰的字段

static修饰的字段是静态字段(Static Field)或类变量(Class Variable)。它属于类级别而不是对象级别,随类加载而存在于方法区(或静态数据区),由所有该类实例所共享,能直接通过类名访问。就不是对象状态的一部分,因此不存在序列化与不序列化的问题。

八、实际应用场景


1. 网络传输

客户端发送对象到服务端:

User对象 → 字节流 → Socket → 服务端

2. Redis缓存

对象 → JSON/字节 → Redis

3. Session共享

Tomcat Session 持久化时:

Session对象 → 序列化 → 磁盘

4. 消息队列

对象 → 序列化 → MQ

九、常见异常


NotSerializableException

原因:

类没实现 Serializable

java.io.NotSerializableException

解决:

implements Serializable

十、JSON序列化 vs Java序列化


Java原生序列化

对象 → 二进制

优点:

  • 简单

缺点:

  • 不跨语言

  • 性能一般

  • 不安全


JSON序列化(更常用)

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);

结果:

{"name":"Tom","age":18}

优点:

  • 可读性高

  • 跨语言

  • 前后端通用


十一、相关问题

image-dhit.png


评论