Java序列化详解

splend21 Lv1

如果我们需要持久化 Java 对象,比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。序列化需要使用到序列化器

在Java中,Serializer(序列化器)是一个广义的概念,指的是将对象状态转换为可存储或可传输格式的过程的工具或组件。它并不是特指某一个框架,而是一种设计模式或功能,可以由不同的库或框架提供。

Java提供了内置的序列化机制(实现java.io.Serializable接口),但也有很多第三方库提供了更高效、跨语言的序列化方案,如JSON(Jackson、Gson)、XML、Protocol Buffers、Kryo等。

下面分别介绍几种常见的序列化方式。

一、Java内置序列化(基于Serializable接口)

使用步骤:

  1. 让需要序列化的类实现java.io.Serializable接口(标记接口,没有方法)。
  2. 使用ObjectOutputStream和ObjectInputStream进行序列化和反序列化。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.io.*;

// 1. 实现Serializable接口
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 序列化版本ID,用于控制版本兼容性
private String name;
private int age;

// 构造方法、getter和setter省略...

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

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

public class JavaSerializationExample {
public static void main(String[] args) {
Person person = new Person("Alice", 30);

// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
oos.writeObject(person);
System.out.println("序列化完成");
} catch (IOException e) {
e.printStackTrace();
}

// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
Person deserializedPerson = (Person) ois.readObject();
System.out.println("反序列化结果: " + deserializedPerson);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}

注意:

  • transient关键字:标记的成员变量不参与序列化。
  • serialVersionUID:用于控制版本,如果序列化和反序列化的版本不一致,会抛出InvalidClassException。

二、JSON序列化(以Jackson为例)

使用Jackson库进行JSON序列化和反序列化。

首先,添加Jackson依赖(Maven):

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version> <!-- 请使用最新版本 -->
</dependency>

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.fasterxml.jackson.databind.ObjectMapper;

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

Person person = new Person("Alice", 30);

// 序列化为JSON字符串
String jsonString = objectMapper.writeValueAsString(person);
System.out.println("JSON字符串: " + jsonString);

// 从JSON字符串反序列化为对象
Person deserializedPerson = objectMapper.readValue(jsonString, Person.class);
System.out.println("反序列化对象: " + deserializedPerson);
}
}

注意:Person类此时不需要实现Serializable接口,但需要有默认构造方法和getter/setter方法(或者通过注解配置)。

三、其他序列化框架

  1. Gson:Google提供的JSON库,用法类似。
  2. Protocol Buffers(protobuf):Google推出的跨语言、高性能的序列化框架,需要先定义.proto文件。
  3. Kryo:专注于Java对象序列化,性能高,但跨语言支持弱。

选择序列化方式时,需考虑以下因素:

  • 性能:序列化/反序列化的速度、字节大小。
  • 可读性:是否需要人类可读的格式(如JSON、XML)。
  • 跨语言:是否需要支持多种编程语言。
  • 兼容性:协议是否向前向后兼容。

四、自定义序列化

在Java内置序列化中,可以通过在类中实现writeObject和readObject方法来自定义序列化过程。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CustomPerson implements Serializable {
private String name;
private int age;

// 构造方法等省略...

private void writeObject(ObjectOutputStream out) throws IOException {
// 自定义序列化逻辑,例如对名字进行加密
String encryptedName = "加密后的名字"; // 实际加密逻辑省略
out.writeObject(encryptedName);
out.writeInt(age);
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
// 自定义反序列化逻辑
String encryptedName = (String) in.readObject();
// 解密逻辑省略...
this.name = "解密后的名字";
this.age = in.readInt();
}
}

总结:

Java中序列化的使用方式多样,根据需求选择合适的序列化框架。内置序列化简单但性能不高,且跨语言能力差;JSON序列化可读性好且跨语言;Protobuf等二进制协议性能高,适合网络传输。

Comments
On this page
Java序列化详解