在 ArrayList
的源码中,elementData
数组被声明为 transient
,即:
transient Object[] elementData;
transient
关键字的作用是 阻止该字段被默认的序列化机制序列化。ArrayList
使用 transient
修饰 elementData
的原因如下:
1. 优化序列化性能:
elementData
是ArrayList
内部用于存储元素的数组,它的长度通常会比实际存储的元素数量大(因为ArrayList
会预留一些空间以支持动态扩容)。- 如果直接序列化整个
elementData
数组,会导致序列化的数据量变大,因为数组中未使用的部分(即null
值)也会被序列化。 - 通过
transient
修饰elementData
,可以避免序列化未使用的数组空间,从而减少序列化后的数据大小,提高性能。
2. 自定义序列化逻辑:
ArrayList
通过实现java.io.Serializable
接口并重写writeObject
和readObject
方法,自定义了序列化和反序列化的逻辑。- 在
writeObject
方法中,ArrayList
只序列化实际存储的元素,而不是整个elementData
数组。 - 在
readObject
方法中,ArrayList
会根据序列化的元素数量重新构建elementData
数组。
示例代码(简化版):
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// 只序列化实际存储的元素
s.defaultWriteObject();
s.writeInt(size); // 写入实际元素数量
for (int i = 0; i < size; i++) {
s.writeObject(elementData[i]); // 写入每个元素
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// 读取实际元素数量并重建 elementData 数组
s.defaultReadObject();
int capacity = s.readInt(); // 读取实际元素数量
elementData = new Object[capacity];
for (int i = 0; i < capacity; i++) {
elementData[i] = s.readObject(); // 读取每个元素
}
}
3. 节省存储空间:
- 由于
elementData
数组的长度通常会大于实际存储的元素数量,直接序列化整个数组会浪费存储空间。 - 通过自定义序列化逻辑,只序列化实际存储的元素,可以显著减少序列化后的数据大小,节省存储空间。
4. 总结:
transient
修饰elementData
是为了避免序列化未使用的数组空间,从而优化序列化性能和节省存储空间。ArrayList
通过自定义writeObject
和readObject
方法,实现了只序列化实际存储的元素,而不是整个数组。
5. 示例:
假设有一个 ArrayList
,其 elementData
数组长度为 10,但只存储了 5 个元素:
- 如果直接序列化
elementData
,会序列化 10 个元素(包括 5 个null
值)。 - 通过自定义序列化逻辑,只序列化 5 个实际存储的元素,从而减少数据量。
6. 扩展:
transient
关键字的作用是阻止字段被默认的序列化机制序列化,通常用于优化序列化性能或保护敏感数据。- 除了
ArrayList
,其他集合类(如HashMap
)也使用了类似的机制来优化序列化。
THE END
暂无评论内容