序列化是将 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 +
'}';
}
}
使用 ObjectOutputStream
、ObjectInputStream
可以将序列化的字节序列写入文件、从文件中读取
// 创建一个 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 维护,部分功能模块可能不够成熟
- 适用场景:高性能需求的应用,实时数据处理,大规模分布式系统,注重序列化安全性和速度的场景