加 transient 是为了跳过默认序列化,由 ArrayList 自行控制只序列化有效元素;因 elementData 常含大量 null 空位,默认序列化会浪费空间和时间,故重写 writeObject/readObject 仅保存 size 及前 size 个元素。

因为 elementData 数组中常存在大量未使用的空位,直接按默认方式序列化会把整个数组(包括 null 元素)一并写入,造成空间和时间浪费。加 transient 是为了跳过默认序列化,由 ArrayList 自己控制只保存有效数据。
核心原因:避免序列化无效空间
ArrayList 的底层是动态数组,容量(capacity)通常大于实际元素个数(size)。比如添加 5 个元素后,elementData.length 可能是 10 或 16,后面位置全是 null。默认序列化会把这些 null 也存进去,而它们毫无意义。
实际做法:手动序列化有效部分
ArrayList 重写了 writeObject 和 readObject 方法,实现精准序列化:
- 先调用
s.defaultWriteObject()序列化 size 等非 transient 字段 - 再用
s.writeInt(size)记录真实元素数量 - 通过
for (int i = 0; i 循环,仅序列化前 size 个元素 - 反序列化时,根据 size 重建数组,并逐个读取元素填充
额外好处:兼顾安全与兼容
这种设计不只是省空间:
立即学习“Java免费学习笔记(深入)”;
- 减少序列化体积,提升网络传输和磁盘存储效率
- 避免因 null 引用导致的反序列化异常或资源泄漏风险
- 在 writeObject 中检查
modCount != expectedModCount,防止并发修改破坏一致性 - 保持与 clone() 行为兼容——size 被当作“逻辑容量”写入,便于后续扩容判断
本质上,transient 不是拒绝序列化,而是把控制权交还给类本身,让序列化更精准、更高效、更可控。


















