序列化方案对比
选型会议上,团队争论不休:
「用 JSON,调试方便」「用 Protobuf,性能好」「用 Kryo,Java 专用最快」「用 Java 原生,最简单」
到底选哪个?这一节给你一张清晰的选型地图。
方案总览
| 特性 | Java 原生 | JSON | Protocol Buffers | Kryo |
|---|---|---|---|---|
| 格式 | 二进制 | 文本 | 二进制 | 二进制 |
| 体积 | 大 | 中 | 极小 | 小 |
| 性能 | 慢 | 较慢 | 快 | 最快 |
| 跨语言 | ❌ | ✅ | ✅ | ❌ |
| 自描述 | ✅ | ✅ | ✅(.proto) | ❌ |
| 序列化ID | serialVersionUID | 无 | 字段编号 | 无 |
| 依赖 | JDK 原生 | Jackson/Gson | protobuf 库 | Kryo 库 |
详细对比
Java 原生序列化
优点:
- JDK 原生,无需任何依赖
- 自动处理引用关系(循环引用)
- 支持版本兼容(serialVersionUID)
- 自动处理对象图序列化
缺点:
- 体积大(含类信息、引用表)
- 速度慢(反射调用、对象表维护)
- 不跨语言(Java 专用格式)
java
// 序列化:JDK 原生
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("data.obj"))) {
oos.writeObject(user);
}JSON(Jackson / Gson)
优点:
- 人类可读,方便调试
- 跨语言,Web API 标配
- 生态丰富,工具链成熟
缺点:
- 体积大(文本格式,含字段名)
- 需要类型信息
- 性能比二进制差
java
// Jackson
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user); // 序列化
User u = mapper.readValue(json, User.class); // 反序列化
// Gson
Gson gson = new Gson();
String json = gson.toJson(user);
User u = gson.fromJson(json, User.class);Protocol Buffers(Protobuf)
优点:
- 体积极小(字段用编号而非名称)
- 性能快(编译时代码生成,无反射)
- 跨语言(.proto 定义接口)
- 向后兼容性好(字段编号机制)
缺点:
- 需要预先定义
.proto文件 - 需要编译步骤
- 对于简单场景,配置成本高
protobuf
// User.proto
syntax = "proto3";
message User {
string name = 1;
int32 age = 2;
string password = 3;
}java
// 序列化
UserProto.User.Builder builder = UserProto.User.newBuilder();
builder.setName("张三");
builder.setAge(25);
byte[] bytes = builder.build().toByteArray();
// 反序列化
UserProto.User user = UserProto.User.parseFrom(bytes);Kryo
优点:
- 二进制格式,体积小
- 性能最快(无反射,直接序列化)
- API 简洁
缺点:
- 不跨语言
- 不同版本 Kryo 序列化结果不兼容
- 需要注册类
java
Kryo kryo = new Kryo();
kryo.register(User.class);
// 序列化
Output output = new Output(new FileOutputStream("user.kryo"));
kryo.writeObject(output, user);
output.close();
// 反序列化
Input input = new Input(new FileInputStream("user.kryo"));
User u = kryo.readObject(input, User.class);
input.close();性能对比
测试数据(来自网络综合测试,仅供参考):
| 方案 | 序列化速度 | 反序列化速度 | 体积(相对值) |
|---|---|---|---|
| Java 原生 | 最慢 | 最慢 | 100% |
| JSON | 较慢 | 较慢 | 300% |
| Kryo | 最快 | 最快 | 20% |
| Protobuf | 快 | 快 | 10% |
(实际性能取决于数据结构和测试场景)
选型建议
┌─────────────────────────────────────────────────────────────────┐
│ 选型口诀: │
│ │
│ 跨语言 + 接口定义严格 → Protobuf │
│ 跨语言 + 调试友好 → JSON │
│ 高性能 + Java 专用 → Kryo │
│ 简单对象 + 零依赖 → Java 原生 │
└─────────────────────────────────────────────────────────────────┘典型应用场景
| 场景 | 推荐方案 |
|---|---|
| Redis 缓存 | Kryo / Java 原生 |
| Dubbo RPC | Hessian / Dubbo 序列化 |
| HTTP API | JSON |
| gRPC | Protocol Buffers |
| Kafka 消息 | JSON / Avro |
| 文件持久化 | Kryo / Java 原生 |
总结
- 性能优先:Kryo(Java 专用)或 Protobuf(跨语言)
- 跨语言通用:JSON 或 Protobuf
- 零依赖:Java 原生序列化
- 接口契约:Protobuf(
.proto即接口定义)
