ArrayList源码解读之elementData

源码解读

/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

注意:

  • elementData是transient修饰的
  • elementData不是private的

被transient修饰的变量不参与序列化和反序列化。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

问题

  1. 为什么用transient修饰elementData,如果实际数据不参与序列化和反序列,那么ArrayList反序列化后没有数据了?
  2. 为什么不使用private修饰elementData,而是包可见呢?

解答

问题1解答:

  • elementData不参与默认的序列化和反序列化,不代表没有进行序列化和反序列化
  • ArrayList在序列化的时候会调用writeObject,直接将size和element写入ObjectOutputStream;反序列化时调用readObject,从ObjectInputStream获取size和element,再恢复到elementData。
  • 不直接用elementData来序列化,而采用上诉的方式来实现序列化是因为elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。

问题2解答:

  • non-private to simplify nested class access为了嵌套类可达,简化内部类访问

原因是内部类虽然可以直接访问外部类的成员,但是当访问的成员是私有的时,是有些不同的。虽然我们在编码时,外部类和内部类是写在同一个源码文件中的,但是要知道的是在编译之后,内部类和外部类会被编译为不同的 class 文件,那么此时如何维持外部类的私有属性在内部类中的可见性?java 使用了 synthetic method 来解决这个问题。当内部类中直接使用了外部类的某个私有成员时,会在外部类中自动生成一个静态方法,方法权限是包可见的,方法参数是外部类的实例,方法实现就是返回了传入实例的该私有变量。这样,在内部类中也可以通过使用此静态方法来访问外部类的私有成员了,当然,前提是内部类要持有外部类对象的引用。同理,外部类中再创建了内部类的对象之后,也是能够直接使用内部类的私有成员和方法的,也是用过 synthetic method 来实现的。这就是 elementData 直接声明为包可见的原因,简化了通过 synthetic method 来访问这一步骤。
参考博客

posted @ 2021-10-22 16:09  衰草寒烟  阅读(629)  评论(0编辑  收藏  举报