Skip to content

集合的序列化与反序列化

什么是序列化

序列化 = 对象 → 字节流(存储/传输)

反序列化 = 字节流 → 对象

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控制序列化行为
节省空间只序列化非空数据

相关链接

基于 VitePress 构建