当前位置: 首页 > 图灵资讯 > java面试题> 金三银四精选java面试题-ArrayList中为什么用transient修饰数组?

金三银四精选java面试题-ArrayList中为什么用transient修饰数组?

来源:图灵教育
时间:2023-11-29 09:37:52
 

ArrayList中为什么用transient修饰数组?

ArrayList 中使用 transient 关键字修饰数组 elementData 是为了控制对象的序列化过程提高性能节省存储空间

  • 性能和效率:elementData 数组是 ArrayList 的内部数据结构,它可能会非常大,但实际上只有一部分用于存储元素。如果不使用 transient 修饰符,整个 elementData 数组将会被序列化,包括未使用的部分,降低了序列化效率
  • 节省内存: 序列化整个 elementData 数组可能会占用大量的内存空间,尤其是当 ArrayList 很大时。使用 transient 可以避免序列化未使用的数组部分,从而节省内存。
  • 隐藏内部实现细节:ArrayList 的设计目标之一是封装其内部实现细节,以防止直接访问和依赖于内部数据结构。使用 transient 可以确保 elementData 不会被序列化,从而保护了 ArrayList 的封装性。

如何序列化 ArrayList?

ArrayList通过两个方法readObject、writeObject自定义序列化和反序列化策略,实际直接使用两个流ObjectOutputStream和ObjectInputStream来进行序列化和反序列化。

private void writeObject(ObjectOutputStream var1) throws IOException {
    // 保存当前 modCount 的值,用于后续检查
    int var2 = this.modCount;
    
    // 执行默认对象序列化,保存除 elementData 数组以外的状态
    var1.defaultWriteObject();
    
    // 写入 ArrayList 的大小(元素数量)
    var1.writeInt(this.size);

    // 遍历 elementData 数组,并逐个写入元素
    for(int var3 = 0; var3 < this.size; ++var3) {
        var1.writeObject(this.elementData[var3]);
    }

    // 检查 modCount 是否发生了变化,如果变化了,抛出异常
    if (this.modCount != var2) {
        throw new ConcurrentModificationException();
    }
}

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
    // 将 elementData 初始化为空数组
    this.elementData = EMPTY_ELEMENTDATA;
    
    // 执行默认对象反序列化,还原除 elementData 数组以外的状态
    var1.defaultReadObject();
    
    // 读取 ArrayList 的大小(元素数量),但未使用此值
    var1.readInt();
    
    // 如果 ArrayList 的大小大于 0,执行以下操作
    if (this.size > 0) {
        // 确保 elementData 数组具有足够的容量来容纳元素
        this.ensureCapacityInternal(this.size);
        
        // 获取 elementData 数组的引用
        Object[] var2 = this.elementData;

        // 从输入流中逐个读取元素并存储到 elementData 数组中
        for(int var3 = 0; var3 < this.size; ++var3) {
            var2[var3] = var1.readObject();
        }
    }
}