什么是序列化(Serialization)?

序列化(Serialization) 是指把对象转换成可以存储或传输的格式,这样数据可以在不同系统之间传输,或者存储到文件、数据库、缓存等地方。
反序列化(Deserialization) 则是序列化的逆过程,即把存储或传输的字节数据转换回对象


为什么需要序列化?

在 Java 里,程序运行时的对象(如 User 类的实例)是存储在 内存(JVM 堆) 里的,而我们经常需要:

  1. 将对象存入文件、数据库(如 MySQL、Redis)。
  2. 在网络上传输对象(如 Web API、RPC 调用)。
  3. 缓存对象(如 Redis、Ehcache)。
  4. 跨进程通信(如 Java RMI)。

但 Java 的对象在内存中是复杂的 数据结构,不能直接存到文件或网络中。
所以,我们需要把对象转换成可以存储或传输的格式,比如:

  • JSON
  • XML
  • 二进制流
  • Protocol Buffers(Protobuf)

这个转换的过程就叫 序列化,反过来恢复对象的过程就是 反序列化


Java 序列化方式

1. Java 自带序列化(JDK 原生)

Java 提供了 Serializable 接口,可以让对象支持 二进制序列化

示例

import java.io.*;

// 让类实现 Serializable 接口
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 "User{name='" + name + "', age=" + age + "}";
    }
}

public class TestSerialization {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 序列化:对象写入文件
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"));
        User user = new User("张三", 25);
        oos.writeObject(user);
        oos.close();

        // 反序列化:从文件读取对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"));
        User deserializedUser = (User) ois.readObject();
        ois.close();

        System.out.println("反序列化后的对象:" + deserializedUser);
    }
}

输出:

反序列化后的对象:User{name='张三', age=25}

这里 Serializable 自动将对象转换成二进制,并存入 user.ser 文件。


2. JSON 序列化(Spring Boot 常用)

在 Web 开发中,最常见的序列化方式是 JSON,因为 JSON 是可读性强、跨平台支持的格式。
Spring Boot 默认使用 Jackson 库来进行 JSON 序列化。

示例

import com.fasterxml.jackson.databind.ObjectMapper;

class User {
    private String name;
    private int age;

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

    public String getName() { return name; }
    public int getAge() { return age; }
}

public class JsonSerialization {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        User user = new User("张三", 25);

        // 序列化:对象 -> JSON
        String jsonString = objectMapper.writeValueAsString(user);
        System.out.println("JSON 序列化:" + jsonString);

        // 反序列化:JSON -> 对象
        User deserializedUser = objectMapper.readValue(jsonString, User.class);
        System.out.println("反序列化后的对象:" + deserializedUser.getName());
    }
}

输出:

JSON 序列化:{"name":"张三","age":25}
反序列化后的对象:张三

这里 ObjectMapper 自动把对象转换成 JSON,并可以反序列化回 Java 对象


3. XML 序列化

如果要把对象转换成 XML(用于 Web Service、配置文件等),可以用 javax.xml.bind.JAXB

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;

@XmlRootElement
class User {
    private String name;
    private int age;

    @XmlElement
    public String getName() { return name; }

    @XmlElement
    public int getAge() { return age; }

    public User() {} // JAXB 需要无参构造器
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class XmlSerialization {
    public static void main(String[] args) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(User.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        User user = new User("张三", 25);
        StringWriter writer = new StringWriter();
        marshaller.marshal(user, writer);

        System.out.println(writer.toString());
    }
}

输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <name>张三</name>
    <age>25</age>
</user>

这里 JAXB 把对象转换成 XML 格式,常用于 Web Service。


4. Protobuf 序列化(高性能)

Google 提供的 Protocol Buffers(Protobuf) 是一种高效的 二进制序列化格式,适用于高性能 RPC 通信:

  • 比 JSON 小 10 倍
  • 速度比 JSON 快 5-10 倍
  • 适用于微服务、网络通信

示例

  1. 定义 .proto 文件
syntax = "proto3";
message User {
    string name = 1;
    int32 age = 2;
}
  1. 用 Protobuf 生成 Java 类
protoc --java_out=. User.proto
  1. 序列化 / 反序列化
User user = User.newBuilder().setName("张三").setAge(25).build();
byte[] data = user.toByteArray(); // 序列化
User newUser = User.parseFrom(data); // 反序列化

总结

序列化方式优点缺点应用场景
Java Serializable自带、简单体积大、不跨语言本地存储、缓存
JSON(Jackson)人类可读、跨语言体积大,速度慢API 传输、日志存储
XML(JAXB)结构清晰、标准化体积大Web Service、配置文件
Protobuf体积小、速度快需要 .proto 定义高性能 RPC、微服务

推荐:

  • Web 开发用 JSON(Jackson)
  • 轻量级网络通信用 Protobuf

你在 Spring Boot 里用的 @JsonSerialize 就是 基于 JSON 的序列化,脱敏序列化本质上就是 在序列化过程中修改数据


Java 里的对象本质上确实是 二进制数据,但它们在 JVM 内存中存储的格式我们需要存储或传输的格式是不一样的,所以仍然需要序列化

为什么 Java 对象是二进制的,还要序列化?

1. JVM 内存中的对象格式和存储/传输的格式不同

  • 在 Java 里,对象在内存中的存储方式JVM 专用的格式,包含:
    • 对象头(Object Header)
    • 对象的字段(Heap Data)
    • 对象方法表(Method Table)
    这些数据结构是 Java 运行时专有,不能直接存储到硬盘或通过网络传输。
  • 但是,当我们要 存储到文件/数据库通过网络传输 时,必须转换成通用格式,比如:
    • JSON(可读性强)
    • XML(标准化)
    • Protobuf(高效传输)
    • 二进制流(Java Serializable

所以,序列化的目的将 JVM 内存中的对象转换成可以长期存储或跨系统传输的格式


2. Java 的内存对象地址和结构不能直接用于存储或传输

  • 在 Java 里,所有对象都存储在 堆内存 中,对象的引用是内存地址,但这些地址在不同的 JVM 或计算机上都是无效的
  • 例如: User user1 = new User("张三", 25); User user2 = user1; user2 只是 user1 的引用(指针),它们指向 同一个内存地址,但这个地址在不同机器上是无效的
  • 如果你直接把 Java 内存地址保存到文件里,下次程序重启,地址会变成无效的,所以必须用序列化把对象转换成可存储的数据格式

3. Java 对象可能包含复杂的数据结构

  • Java 的对象不只是简单的二进制数据,还可能包含:
    • 集合(List、Map)
    • 继承关系
    • 循环引用
    • 自定义类
    如果没有序列化规则,存储这些复杂结构就会非常困难

例如,下面的 User 对象里有一个 Address 对象:

class Address {
    String city;
}

class User {
    String name;
    Address address;
}

如果直接把 User 作为二进制存储,它的 address 可能是一个内存地址,无法恢复成原始对象。
但是,序列化可以把 address 变成标准数据格式

{
    "name": "张三",
    "address": {
        "city": "北京"
    }
}

这样,不管在哪台机器上都可以正确反序列化


4. 序列化让 Java 对象可以跨语言、跨平台使用

如果没有序列化,不同的编程语言之间无法直接理解 Java 对象

示例

  • Java 服务器 需要把 User 发送给 Python 客户端
  • 如果没有序列化,Java 只能传递二进制的 JVM 对象,Python 无法理解。
  • 但如果用 JSON 或 Protobuf 进行序列化,Python 就能解析:
    • Java 序列化 JSON{"name": "张三", "age": 25}
    • Python 反序列化 JSONimport json data = '{"name": "张三", "age": 25}' user = json.loads(data) print(user["name"]) # 张三

结论:序列化让 Java 对象可以跨平台使用,不受 JVM 限制。


总结

问题解释
Java 对象是二进制的,为什么还要序列化?Java 内存对象的格式是 JVM 专用的,不能直接存储或传输。
为什么不能直接存对象的二进制?因为 Java 对象包含 指针、内存地址、方法表,不同 JVM 不兼容。
为什么 JSON / XML / Protobuf 更好?因为它们是 标准格式,可以跨语言、跨平台存储和传输。
序列化的好处?让对象可以存入数据库、文件、网络传输,并能恢复回来。

所以,序列化的本质就是把 JVM 里的“内存对象”转换成“可存储和传输的标准格式”,以便数据持久化和跨平台使用!

Categories:

Tags:

暂时没有回复

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注