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型的变量是被包括进去的。
问题
- 为什么用transient修饰
elementData
,如果实际数据不参与序列化和反序列,那么ArrayList反序列化后没有数据了? - 为什么不使用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 来访问这一步骤。
参考博客