Java 常用序列化:揭开底层实现的神秘面纱

56 阅读2分钟

Java 中常用的序列化方式主要包括以下几种:

1. Java 原生序列化

使用方式:

使用 java.io.Serializable 接口。对象需要实现该接口,然后通过 ObjectOutputStreamObjectInputStream 进行序列化和反序列化。

示例代码:

import java.io.*;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;

    // 构造方法、getter 和 setter 方法

    public static void main(String[] args) {
        Person person = new Person("John", 30);
        
        // 序列化(`FileOutputStream` 是一个字节流类,用于将数据写入文件。在这里,它指定了文件名 `"person.ser"`)
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
            oos.writeObject(person);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
            Person deserializedPerson = (Person) ois.readObject();
            System.out.println(deserializedPerson.getName() + ", " + deserializedPerson.getAge());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

底层实现原理:

  • Java 原生序列化采用的是从对象中提取字段数据,并将这些数据以字节流的形式存储下来。
  • ObjectOutputStream 将对象转换为字节流,ObjectInputStream 将字节流恢复为对象。
  • 序列化过程中,Java 会记录对象类型信息和对象引用关系,以支持复杂对象图的序列化和反序列化。

2. JSON 序列化

使用方式:

使用第三方库,如 FastJson、Jackson 或 Gson,将对象转换为 JSON 字符串,再将 JSON 字符串还原为对象。

示例代码(使用 Jackson):

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonExample {
    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        Person person = new Person("John", 30);

        // 序列化
        try {
            String jsonString = mapper.writeValueAsString(person);
            System.out.println(jsonString);

            // 反序列化
            Person deserializedPerson = mapper.readValue(jsonString, Person.class);
            System.out.println(deserializedPerson.getName() + ", " + deserializedPerson.getAge());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

底层实现原理:

  • 利用反射机制,根据对象的字段信息生成相应的 JSON 格式字符串。
  • 反序列化时,这些库会解析 JSON 字符串,并利用反射创建对象实例并赋值给其字段。

3. ProtoBuf 序列化

使用方式:

使用 Google 的 Protocol Buffers(ProtoBuf)来定义消息格式,并生成相应的 Java 类。

示例代码:

首先定义一个 .proto 文件:

syntax = "proto3";

message Person {
  string name = 1;
  int32 age = 2;
}

然后使用 protoc 工具生成 Java 类,并进行序列化/反序列化:

import com.example.PersonOuterClass.Person;

public class ProtoBufExample {
    public static void main(String[] args) {
        Person person = Person.newBuilder().setName("John").setAge(30).build();
        
        // 序列化
        byte[] byteArray = person.toByteArray();
        
        // 反序列化
        try {
            Person deserializedPerson = Person.parseFrom(byteArray);
            System.out.println(deserializedPerson.getName() + ", " + deserializedPerson.getAge());
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
    }
}

底层实现原理:

  • ProtoBuf 采用预定义的二进制格式,具有良好的跨语言兼容性。
  • 在编译 .proto 文件时,会生成对应的 Java 类,这些类包含序列化和反序列化的方法。
  • ProtoBuf 在序列化时会将数据按照字段编号编码成紧凑的二进制格式,反序列化时则根据字段编号恢复对象数据。