前端视角 Java Web 入门手册 2.8:Java Core ——序列化与反序列化

113 阅读4分钟

序列化是将 Java 对象转换为一系列字节的过程,这些字节可以被存储在文件、数据库中,或者通过网络传输到远程系统。序列化的主要目的是持久化对象状态或在分布式环境中传输对象。

反序列化是序列化的逆过程,即将字节序列重新转换为 Java 对象。通过反序列化,可以恢复对象的原始状态,继续在程序中使用。

序列化、反序列化有几个主要应用场景

  • 持久化:将对象状态保存到磁盘或数据库中,便于后续恢复
  • 网络通信:序列化可以使得对象在网络中可传输,从而方便地实现客户端和服务器之间的通信
  • 缓存:将对象序列化后存储到缓存中,提高访问速度
  • 深拷贝:通过序列化和反序列化实现对象的深拷贝

Java 内置序列化

Java 提供了内置的序列化机制,通过实现特定接口和遵循一定的约定,开发者可以轻松实现对象的序列化与反序列化

  • 实现 Serializable 接口
  • 所有字段可序列化,不需要的使用关键字transient修饰
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

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

使用 ObjectOutputStreamObjectInputStream 可以将序列化的字节序列写入文件、从文件中读取

// 创建一个 Person 对象,并设置属性
Person person = new Person();
person.setName("张三");
person.setAge(18);

// 序列化 Person 对象
FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(person);
oos.close();
fos.close();
System.out.println("Person 对象已经被序列化到 person.ser 文件中。");

// 反序列化 Person 对象
FileInputStream fis = new FileInputStream("person.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Person newPerson = (Person) ois.readObject();
ois.close();
fis.close();
System.out.println("person.ser 文件中的 Person 对象已经被反序列化。");
System.out.println("反序列化后的 Person 对象:" + newPerson);

serialVersionUID

serialVersionUID 是一个唯一的标识符,用于确保序列化和反序列化过程的版本兼容性。当类的结构发生变化时,如果没有显式声明 serialVersionUID,Java 会根据类的信息自动生成一个。然而,这种自动生成的方式在类结构稍作修改时可能导致不兼容的问题,因此推荐显式声明

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 123456789L; // 显式声明

    private String name;
    private int age;
    
    // 其他代码...
}

社区方案

因为几个明显缺陷,实际开发中很少使用 JDK 自带的序列化、反序列化工具

  • Java 特有,无法跨语言序列化、反序列化
  • 处理大量数据时性能较差,序列化后字节体积大,增加传输成本
  • 存在部分安全问题,攻击者可以通过构造恶意序列化对象来实现远程代码执行

业界流行的序列化、反序列化工具非常多,Gson、jackson、Apache Thrift、fastjson 等

Jackson

Jackson 是 Java 中最流行的 JSON 处理库之一,功能强大、性能优越

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonExample {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();

        // 创建对象
        User user = new User("Alice", 30);

        // 序列化
        String jsonString = mapper.writeValueAsString(user);
        System.out.println("Jackson JSON 字符串: " + jsonString);
        // 输出: {"name":"Alice","age":30}

        // 反序列化
        String jsonInput = "{"name":"Bob","age":25}";
        User deserializedUser = mapper.readValue(jsonInput, User.class);
        System.out.println("Jackson 反序列化对象: " + deserializedUser);
        // 输出: User{name='Bob', age=25}
    }
}
  • 优点:功能强大,支持复杂的数据绑定和多种数据格式,性能优越,社区活跃
  • 缺点:学习曲线较陡,API 较为复杂
  • 适用场景:企业级应用,复杂对象映射,多格式数据处理,性能要求较高的场景

Gson

Gson 是 Google 开发的一个开源 Java 库

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GsonExample {
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        // 创建对象
        User user = new User("Charlie", 28);

        // 序列化
        String jsonString = gson.toJson(user);
        System.out.println("Gson JSON 字符串:\n" + jsonString);
        // 输出:
        // {
        //   "name": "Charlie",
        //   "age": 28
        // }

        // 反序列化
        String jsonInput = "{"name":"Dana","age":22}";
        User deserializedUser = gson.fromJson(jsonInput, User.class);
        System.out.println("Gson 反序列化对象: " + deserializedUser);
        // 输出: User{name='Dana', age=22}
    }
}
  • 优点:易用性高,API 简洁,自动处理泛型,良好的兼容性
  • 缺点:性能相对较低,扩展性有限
  • 适用场景:中小型项目,快速开发,Android 开发等需要轻量级 JSON 处理的场景

Fastjson

Fastjson2 是阿里巴巴的开源 JSON 解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean

import com.alibaba.fastjson2.JSON;

public class Fastjson2Example {
    public static void main(String[] args) {
        // 创建对象
        User user = new User("Eve", 35);

        // 序列化
        String jsonString = JSON.toJSONString(user);
        System.out.println("Fastjson2 JSON 字符串: " + jsonString);
        // 输出: {"age":35,"name":"Eve"}

        // 反序列化
        String jsonInput = "{"name":"Frank","age":40}";
        User deserializedUser = JSON.parseObject(jsonInput, User.class);
        System.out.println("Fastjson2 反序列化对象: " + deserializedUser);
        // 输出: User{name='Frank', age=40}
    }
}
  • 优点:极高的性能远超 Jackson 和 Gson,支持丰富的配置与扩展,安全性改进显著
  • 缺点:相较于 Jackson,社区和生态不活跃,主要 Alibaba 维护,部分功能模块可能不够成熟
  • 适用场景:高性能需求的应用,实时数据处理,大规模分布式系统,注重序列化安全性和速度的场景