Java序列化和反序列化
核心概念
什么是序列化?
对象序列化机制(Object Serialization)是Java语言内建的一种对象持久化机制,它能够:
- 序列化:将对象的状态转换为字节序列(byte stream)
- 反序列化:将字节序列重新转换为对象实例
- 用途:对象存储、网络传输、缓存、深拷贝等
序列化流程图
序列化 存储/传输 读取 反序列化 Java对象 字节序列 文件/网络/缓存 字节序列 Java对象
序列化实现
基本要求
- 实现Serializable接口:标记接口,无需实现任何方法
- 使用ObjectOutputStream:将对象写入字节流
- 处理序列化异常:IOException等
序列化过程
java
// 1. 对象实现Serializable接口
// 2. 创建ObjectOutputStream
// 3. 调用writeObject()方法
// 4. 关闭流资源
反序列化实现
基本要求
- 类路径可访问:反序列化时类必须在classpath中
- 使用ObjectInputStream:从字节流读取对象
- 版本兼容性:serialVersionUID必须匹配
反序列化过程
java
// 1. 创建ObjectInputStream
// 2. 调用readObject()方法
// 3. 强制类型转换
// 4. 关闭流资源
代码示例
基础序列化示例
java
import java.io.*;
/**
* 用户实体类 - 演示基础序列化
*/
public class User implements Serializable {
// 序列化版本号
private static final long serialVersionUID = 1L;
private String username;
private String email;
// 敏感信息不序列化
private transient String password;
// 静态变量不序列化
private static String company = "TechCorp";
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
// getter/setter方法省略...
@Override
public String toString() {
return String.format("User{username='%s', email='%s', password='%s', company='%s'}",
username, email, password, company);
}
}
序列化工具类
java
import java.io.*;
/**
* 序列化工具类
*/
public class SerializationUtil {
/**
* 序列化对象到文件
*/
public static <T> void serializeToFile(T object, String filePath) throws IOException {
try (FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(object);
}
}
/**
* 从文件反序列化对象
*/
@SuppressWarnings("unchecked")
public static <T> T deserializeFromFile(String filePath) throws IOException, ClassNotFoundException {
try (FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream ois = new ObjectInputStream(fis)) {
return (T) ois.readObject();
}
}
/**
* 序列化对象到字节数组
*/
public static <T> byte[] serializeToBytes(T object) throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
return baos.toByteArray();
}
}
/**
* 从字节数组反序列化对象
*/
@SuppressWarnings("unchecked")
public static <T> T deserializeFromBytes(byte[] data) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais)) {
return (T) ois.readObject();
}
}
/**
* 深拷贝实现 - 通过序列化
*/
@SuppressWarnings("unchecked")
public static <T> T deepCopy(T object) throws IOException, ClassNotFoundException {
byte[] data = serializeToBytes(object);
return deserializeFromBytes(data);
}
}
完整使用示例
java
public class SerializationDemo {
public static void main(String[] args) {
try {
// 创建用户对象
User originalUser = new User("john_doe", "john@example.com", "secret123");
System.out.println("原始对象: " + originalUser);
// 序列化到文件
SerializationUtil.serializeToFile(originalUser, "user.ser");
System.out.println("序列化完成");
// 从文件反序列化
User deserializedUser = SerializationUtil.deserializeFromFile("user.ser");
System.out.println("反序列化对象: " + deserializedUser);
// 深拷贝示例
User copiedUser = SerializationUtil.deepCopy(originalUser);
System.out.println("深拷贝对象: " + copiedUser);
// 验证是否为不同对象
System.out.println("是否为同一对象: " + (originalUser == copiedUser));
System.out.println("内容是否相等: " + originalUser.equals(copiedUser));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
核心特性详解
1. Serializable接口
- 标记接口:无方法定义,仅作为序列化标识
- 必要条件:只有实现此接口的类才能被序列化
- 继承性:子类自动继承父类的序列化能力
2. transient关键字
java
public class SecurityUser implements Serializable {
private String username;
// 不会被序列化
private transient String password;
// 临时数据不序列化
private transient String sessionId;
// 反序列化后,transient字段会被初始化为默认值
// String -> null, int -> 0, boolean -> false
}
3. serialVersionUID详解
java
public class VersionedClass implements Serializable {
// 显式声明版本号
private static final long serialVersionUID = 1L;
private String name;
// 后续版本可以安全添加新字段
// 新增字段,版本号不变
private String newField;
}
版本兼容性规则:
- 相同版本号:允许反序列化
- 不同版本号 :抛出
InvalidClassException
- 未声明版本号:JVM自动生成,类结构变化会导致不兼容
4. 静态变量处理
java
public class StaticFieldExample implements Serializable {
private static final long serialVersionUID = 1L;
private String instanceField = "实例字段";
// 不会被序列化
private static String staticField = "静态字段";
// 静态变量属于类级别,不属于对象状态
// 反序列化时使用当前类加载时的静态变量值
}
5. 继承关系处理
java
// 父类不实现Serializable
class Parent {
protected String parentField = "parent";
// 必须有无参构造器,反序列化时会调用
public Parent() {}
}
// 子类实现Serializable
class Child extends Parent implements Serializable {
private static final long serialVersionUID = 1L;
private String childField = "child";
// 只有子类字段会被序列化
// 父类字段在反序列化时通过无参构造器初始化
}
性能优化策略
1. 选择合适的序列化方案
java
// 性能对比(仅供参考)
// Java原生序列化:功能完整,性能一般
// JSON序列化:可读性好,跨语言支持
// Protocol Buffers:高性能,体积小
// Kryo:Java专用,性能优秀
public class SerializationBenchmark {
public static void comparePerformance() {
// 1. Java原生序列化 - 通用但较慢
// 2. JSON (Jackson/Gson) - 可读性好
// 3. Kryo - Java高性能序列化
// 4. Protocol Buffers - 跨语言高性能
}
}
2. 减少序列化数据量
java
public class OptimizedData implements Serializable {
private static final long serialVersionUID = 1L;
// 使用transient减少序列化数据
private String data;
private transient String derivedData; // 可计算得出的数据
private transient Object heavyObject; // 大对象不序列化
// 自定义序列化逻辑
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
// 只序列化核心数据
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
// 重建派生数据
this.derivedData = computeDerivedData();
this.heavyObject = createHeavyObject();
}
}