当前位置: 首页 > backend >正文

Java 序列化与反序列化终极解析

Java 序列化与反序列化终极解析

1. 核心概念

(1) 什么是序列化?

  • 定义:将对象转换为字节流的过程(对象 → 字节)

  • 目的

    • 持久化存储(如保存到文件)

    • 网络传输(如RPC调用)

    • 深拷贝实现

(2) 什么是反序列化?

  • 定义:将字节流还原为对象的过程(字节 → 对象)

  • 关键点

    • 不会调用构造方法

    • 字段值直接从字节流读取

2. 核心API

(1) 序列化相关类

类/接口作用
Serializable标记接口(无方法)
Externalizable提供自定义序列化(需实现2个方法)
ObjectOutputStream序列化输出流
ObjectInputStream反序列化输入流

(2) 关键方法

java

// 序列化
objectOutputStream.writeObject(obj);// 反序列化
Object obj = objectInputStream.readObject();

3. 完整流程解析

(1) 序列化流程

  1. 检查对象是否实现Serializable

  2. 递归序列化所有非transient字段

  3. 写入类描述信息(含serialVersionUID

  4. 写入字段数据

(2) 反序列化流程

  1. 读取并验证serialVersionUID

  2. 分配对象内存(不调用构造方法)

  3. 递归填充字段值

  4. 对于Externalizable对象,调用readExternal()

4. 代码示例

(1) 基础序列化

java

// 可序列化类
class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private transient int age; // 不参与序列化// 构造方法、getter/setter省略
}// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) {oos.writeObject(new Person("Alice", 25));
}// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) {Person p = (Person) ois.readObject();System.out.println(p.getName()); // 输出AliceSystem.out.println(p.getAge()); // 输出0(transient字段)
}

(2) 自定义序列化(Externalizable)

java

class Student implements Externalizable {private String name;// 必须有无参构造器public Student() {}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeUTF(name);}@Overridepublic void readExternal(ObjectInput in) throws IOException {this.name = in.readUTF();}
}

5. 关键机制

(1) serialVersionUID

  • 作用:版本控制,防止类结构变更导致反序列化失败

  • 生成方式

    • 显式声明:private static final long serialVersionUID = 1L;

    • 隐式生成:根据类结构计算hash值

(2) 序列化规则

字段类型是否序列化说明
普通实例字段
transient字段如密码字段
static字段属于类而非对象
未实现Serializable抛出异常所有引用字段必须可序列化

6. 高级特性

(1) 自定义序列化

java

private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject(); // 默认序列化out.writeUTF(encrypt(password)); // 自定义处理
}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject(); // 默认反序列化this.password = decrypt(in.readUTF()); // 自定义处理
}

(2) 序列化代理模式

java

private Object writeReplace() {return new SerializationProxy(this);
}private static class SerializationProxy implements Serializable {private final String data;SerializationProxy(OriginalClass obj) {this.data = obj.getData();}private Object readResolve() {return new OriginalClass(data);}
}

7. 常见问题与解决方案

(1) 反序列化漏洞

  • 风险:攻击者可能构造恶意字节流执行任意代码

  • 防护

    • 使用ObjectInputFilter设置白名单

    java

ObjectInputFilter filter = info -> info.serialClass() == Person.class ? Status.ALLOWED : Status.REJECTED;
ois.setObjectInputFilter(filter);

(2) 性能优化

  • 替代方案

    • JSON(Jackson/Gson)

    • 二进制协议(Protocol Buffers)

    • Kryo(高性能Java序列化)

8. 记忆技巧

(1) 核心口诀

"序列化要接口,transient能跳过
static不算数,UID保平安
构造方法不执行,字段直接写内存"

(2) 流程图解

复制

序列化:
[对象] → [检查Serializable] → [写入元数据] → [递归写字段] → [字节流]反序列化:
[字节流] → [验证UID] → [分配内存] → [填充字段] → [返回对象]

9. 面试高频问题

  1. Q: 反序列化时如何避免调用构造方法?
    A: JVM直接分配内存并从字节流填充数据

  2. Q: 为什么Serializable是空接口?
    A: 标记接口,仅用于类型检查

  3. Q: 如何实现深拷贝?
    A: 序列化后再反序列化

  4. QExternalizableSerializable区别?
    A: 前者需实现方法,后者自动序列化

10. 最佳实践

  1. 安全性

    • 敏感字段标记transient

    • 使用ObjectInputFilter

  2. 版本控制

    • 始终显式声明serialVersionUID

  3. 性能

    • 避免序列化大对象

    • 考虑替代方案(如ProtoBuf)

  4. 代码健壮性

    • 实现readObject()时保持防御性编程

    • 对不可变对象使用序列化代理模式

通过这个完整体系,你已掌握Java序列化的:
✅ 核心机制 ✅ 安全风险 ✅ 性能优化 ✅ 工程实践

http://www.xdnf.cn/news/285.html

相关文章:

  • 每日两道leetcode
  • 4.17-4.18学习总结 多线程
  • STP协议中的四种端口状态
  • 熵权法+TOPSIS+灰色关联度综合算法(Matlab实现)
  • 在 Babylon.js 中实现智能异步资源加载队列管理
  • 力扣DAY56-59 | 热100 | 回溯:子集、电话号码的字母组合、组合总和、括号生成
  • 【裁判文书网DES3数据解密】逆向分析
  • windwos脚本 | 基于scrcpy,只投声音、只投画面
  • MySQL中高级语法
  • 博客标题栏添加一个 About Me
  • RUI桌面TV版最新版免费下载-安卓电视版使用教程
  • 二叉树理论基础
  • static关键字
  • qt QGroupButton 实现两个QPushButton的互斥
  • 动态计算FPS(每秒帧数)的方法
  • Jsp技术入门指南【六】jsp脚本原理及隐式对象
  • 关于AI提示工程的详解,分点说明其核心概念、关键技巧和应用场景
  • 语音合成之二TTS模型损失函数进化史
  • 极狐GitLab 项目和群组的导入导出速率限制如何设置?
  • Linux 文件查找终极指南:find, locate, grep 等命令详解
  • 18-算法打卡-哈希表-两数之和-leetcode(1)-第十八天
  • 智能体时代的产业范式确立,中国企业以探索者姿态走出自己的路
  • [密码学实战]详解gmssl库与第三方工具兼容性问题及解决方案
  • Python语言基础教程(上)4.0
  • 15.4K Star!Vercel官方出品,零基础构建企业级AI聊天机器人
  • 进程(转账,卖票)
  • C#核心笔记——(六)框架基础
  • 【MySQL】数据库和表的操作详解
  • 6.6 “3步调用ChatGPT打造高可靠Python调度器,零依赖实现定时任务自动化“
  • Linux工具学习之【vim】