
什么是序列化和反序列化?
想象一下你要给远方的朋友寄送一个复杂的乐高模型。你不能直接把拼好的模型寄过去,由于运输途中会散架。你需要:
- 序列化:把乐高模型拆成一个个零件,按照说明书编号整理(对象 → 字节序列)
- 运输:把零件装箱寄出(网络传输或存储到文件)
- 反序列化:朋友收到后,按照说明书重新拼装(字节序列 → 对象)
在编程世界中,序列化就是把内存中的对象转换成可以存储或传输的格式,反序列化则是相反的过程。
为什么需要序列化?
主要应用场景:
- 网络传输:微服务之间传递对象数据
- 数据持久化:将对象保存到文件或数据库
- 缓存存储:Redis等缓存系统中的对象存储
- 分布式计算:Spark、Hadoop中的数据传输
- 会话管理:Web应用中的Session存储
Java 原生序列化机制
基本用法:实现 Serializable 接口
import java.io.*;
// 1. 实现 Serializable 标记接口
public class User implements Serializable {
// 2. 提议显式声明序列化版本ID
private static final long serialVersionUID = 1L;
private String name;
private int age;
private transient String password; // transient修饰的字段不会被序列化
// 构造方法、getter、setter...
public User(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + ", password='" + password + "'}";
}
}
序列化操作示例
public class SerializationDemo {
// 序列化:对象 -> 字节序列
public static void serializeUser(User user, String filename) throws IOException {
try (FileOutputStream fileOut = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(user);
System.out.println("对象序列化完成,保存到: " + filename);
}
}
// 反序列化:字节序列 -> 对象
public static User deserializeUser(String filename)
throws IOException, ClassNotFoundException {
try (FileInputStream fileIn = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(fileIn)) {
User user = (User) in.readObject();
System.out.println("对象反序列化完成");
return user;
}
}
public static void main(String[] args) {
User originalUser = new User("张三", 25, "secret123");
try {
// 序列化
serializeUser(originalUser, "user.ser");
// 反序列化
User restoredUser = deserializeUser("user.ser");
System.out.println("原始对象: " + originalUser);
System.out.println("恢复对象: " + restoredUser);
System.out.println("password字段被transient修饰: " +
(restoredUser.toString().contains("null")));
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
对象序列化完成,保存到: user.ser
对象反序列化完成
原始对象: User{name='张三', age=25, password='secret123'}
恢复对象: User{name='张三', age=25, password='null'}
password字段被transient修饰: true
序列化机制解析
serialVersionUID 的重大性
public class SerialVersionUIDDemo {
// 场景1:没有显式声明serialVersionUID
public static class Book implements Serializable {
private String title;
private String author;
// 如果后续添加新字段,反序列化可能失败
}
// 场景2:显式声明serialVersionUID(推荐)
public static class SafeBook implements Serializable {
private static final long serialVersionUID = 123456789L;
private String title;
private String author;
// 即使后续添加字段,只要UID不变,反序列化仍能兼容
private String isbn; // 新增字段
}
}
serialVersionUID 的作用:
- 版本控制:确保序列化和反序列化的类版本一致
- 兼容性:当类结构变化时,通过控制UID来管理兼容性
- 安全验证:防止恶意篡改序列化数据
自定义序列化过程
public class CustomSerializationDemo implements Serializable {
private static final long serialVersionUID = 1L;
private String sensitiveData;
private transient String temporaryData;
// 自定义序列化逻辑
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // 默认序列化
// 加密敏感数据
String encrypted = encrypt(sensitiveData);
oos.writeObject(encrypted);
}
// 自定义反序列化逻辑
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // 默认反序列化
// 解密数据
String encrypted = (String) ois.readObject();
this.sensitiveData = decrypt(encrypted);
}
private String encrypt(String data) {
// 简单的加密演示(实际应用应使用安全算法)
return Base64.getEncoder().encodeToString(data.getBytes());
}
private String decrypt(String data) {
return new String(Base64.getDecoder().decode(data));
}
}
序列化就像是对象的”语言翻译器”,让对象能在不同的”世界”(网络、文件、进程)中旅行。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END














暂无评论内容