集合的序列化与反序列化
什么是序列化
序列化 = 对象 → 字节流(存储/传输)
反序列化 = 字节流 → 对象
java
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(collection);
byte[] bytes = baos.toByteArray();
// 反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Collection c = (Collection) ois.readObject();ArrayList 的序列化
ArrayList 实现了 Serializable,底层数组是 transient(不自动序列化),但 JDK 通过 readObject/writeObject 自定义序列化逻辑。
java
transient Object[] elementData; // 不自动序列化
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(size);
// 只序列化有数据的元素,不序列化空数组位置
for (int i = 0; i < size; i++) {
s.writeObject(elementData[i]);
}
}HashMap 的序列化
HashMap 同样使用 transient 和自定义 writeObject/readObject:
java
transient Node<K, V>[] table;
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(size);
s.writeFloat(loadFactor);
// 只序列化非空桶
for (Map.Entry<K, V> e : entrySet()) {
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
}为什么要自定义序列化
ArrayList/HashMap 的数组容量可能远大于实际元素数量:
java
ArrayList<String> list = new ArrayList<>();
list.add("hello");
// 容量可能是 10,实际只有 1 个元素
HashMap<String, Integer> map = new HashMap<>();
map.put("a", 1);
// 容量可能是 16,实际只有 1 个元素如果直接序列化整个数组/桶数组,会浪费大量空间。自定义序列化只序列化实际数据。
性能对比
java
// 容量 10000,存储 10 个元素
ArrayList<String> list = new ArrayList<>(10000);
for (int i = 0; i < 10; i++) list.add("item");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(list);
System.out.println("序列化字节数: " + baos.toByteArray().length);
// 典型输出:约 200 字节(只序列化 10 个元素)
// 如果序列化整个数组(10000 个位置),会是约 200000 字节总结
| 要点 | 说明 |
|---|---|
| transient | 标记不自动序列化的字段 |
| 自定义 writeObject/readObject | 控制序列化行为 |
| 节省空间 | 只序列化非空数据 |
