一、 序列化(Serialization)
将 Java 对象转换为字节流的过程,使其能够被存储(如保存到文件、数据库)或传输(如网络通信)。
作用:持久化对象状态、跨平台传输、支持分布式计算(如 RPC)
技术要求:
- 类需实现
java.io.Serializable
标记接口(无方法,仅标识可序列化)。 - 使用
ObjectOutputStream.writeObject()
将对象写入字节流。 - 可通过
transient
关键字排除敏感或临时字段。
二、反序列化(Deserialization)
将字节流恢复为内存中的 Java 对象的过程。
作用:重建对象状态、接收远程数据、恢复持久化数据
技术要求:
- 使用
ObjectInputStream.readObject()
从字节流读取对象。 - 反序列化的类需与序列化时的类结构兼容(否则抛出
InvalidClassException
)。 - 显式定义
serialVersionUID
控制版本一致性,避免类定义变更导致兼容性问题。
三、两者关系
维度 | 序列化 | 反序列化 |
---|---|---|
目的 | 对象 → 字节流(存储/传输) | 字节流 → 对象(恢复/使用) |
接口依赖 | 类必须实现 Serializable | 同序列化要求,且需保证类定义兼容性 |
核心方法 | ObjectOutputStream.writeObject() | ObjectInputStream.readObject() |
数据控制 | transient 字段不参与序列化 | 依赖序列化时的字段值重建对象 |
安全风险 | 暴露敏感字段(若未用 transient ) | 不可信数据可能导致代码执行漏洞(需验证来源或使用白名单) |
典型应用 | 保存对象到文件、发送网络请求、缓存数据 | 读取文件恢复对象、接收网络数据、反序列化缓存 |
注意事项
- 兼容性:若序列化后修改类结构(如增删字段),需保持
serialVersionUID
一致,否则反序列化失败。- 性能:Java 原生序列化可能效率较低,跨语言场景建议使用 JSON/XML 或高效二进制协议。
- 安全性:避免反序列化不可信数据,防止攻击者构造恶意字节流触发漏洞。
通过序列化与反序列化,Java 实现了对象状态的持久化和跨环境交互,是分布式系统、缓存机制等场景的底层基础技术。
四、数据持久化应用
1、封装序列化和反序列化方法(使用泛型)
package org.ser;
import java.io.*;
public class InitSerialize {
/**
* 序列化对象
*
* @param obj 对象
* @param path 路径
*/
public <T> void serializeObject(T obj, String path) {
// 序列化对象到文件
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));) {
// 写入对象到文件
oos.writeObject(obj);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 反序列化对象
*
* @param path 路径
* @param <T> 泛型类型
* @return
*/
public <T> T deserializeObject(String path) {
// 反序列化对象
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path))) {
// 读取对象
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
2、用户类实现序列化接口
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
// private transient int age; // 不会被序列化
private int age; //
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
}
3、测试类
package org.ser;
import java.util.Arrays;
import java.util.List;
public class TestSer {
public static void main(String[] args) {
//实例化对象
InitSerialize initSerialize = new InitSerialize();
//单个对象的操作
one(initSerialize);
//多个对象的操作
// more(initSerialize);
}
private static void one(InitSerialize initSerialize) {
//用户对象
User user = new User("Sergey", 25);
//序列化对象到文件
initSerialize.serializeObject(user, "user.ser");
//反序列化对象从文件
User user1 = initSerialize.deserializeObject("user.ser");
System.out.println(user1);
}
private static void more(InitSerialize initSerialize) {
//多个对象的操作
User user2 = new User("mike", 20);
User user3 = new User("boy", 18);
User user4 = new User("girl", 19);
User user5 = new User("little", 17);
//对象数组
User[] users = new User[]{user2, user3, user4, user5};
//序列化对象数组到文件
initSerialize.serializeObject(users, "users.ser");
//反序列化对象数组从文件
User[] users1 = initSerialize.deserializeObject("users.ser");
//将数组转换为列表
List<User> list = Arrays.asList(users1);
//Lambda表达式遍历并打印用户信息
list.forEach(System.out::println);
}
}
4、运行