ArrayList/Vector的底层分析(加了些自己的理解)

2018/10 08 18:10

一、ArrayList
ArrayList 实现于 List、RandomAccess(标记接口) 接口。可以插入空数据,也支持随机访问。
RandomAccess接口的意义在于:在对列表进行随机或顺序访问的时候,访问算法能够选择性能最佳方式。

ArrayList相当于动态数据,其中最重要的两个属性分别是: elementData 数组,以及 size 大小。 在调用 add() 方法的时候:

  • 首先进行扩容校验。
  • 将插入的值放到尾部,并将 size + 1 。

注意:如果 new ArrayList(int initialCapacity),指定初始大小后立刻调用add方法,初始大小值小于10,对于节省内存空间是没有意义的。ensureCapacityInternal()方法会报elementData调整成默认容量10。

如果是调用add(index,e)在指定位置添加的话:

  • 也是首先扩容校验。
  • 接着对数据进行复制,目的是把 index 位置空出来放本次插入的数据,并将后面的数据向后移动一个位置。

其实扩容最终调用的代码:

也是一个数组复制的过程。

由此可见ArrayList的主要消耗是数组扩容以及在指定位置添加数据,在日常使用时最好是指定大小,尽量减少扩容。更要减少在指定位置插入数据的操作。

二、ArrayList序列化

由于 ArrayList 是基于动态数组实现的,所以并不是所有的空间都被使用。因此使用了transient 修饰,可以防止被自动序列化。

因此 ArrayList 自定义了序列化与反序列化:

注意:当对象中自定义了 writeObject 和 readObject 方法时,JVM 会调用这两个自定义方法来实现序列化与反序列化。

从实现中可以看出 ArrayList 只序列化了被使用的数据。

四、Vector

Vector也是实现于List接口,底层数据结构和ArrayList类似,也是一个动态数组存放数据。不过是在add()方法的时候使用synchronized进行同步写数据,但是开销较大,所以Vector是一个同步容器并不是一个并发容器。

以下是add()方法:

以及指定位置插入数据:

 

--转载请注明: https://www.guangboyuan.cn/arraylistvector%e7%9a%84%e5%ba%95%e5%b1%82%e5%88%86%e6%9e%90%ef%bc%88%e5%8a%a0%e4%ba%86%e4%ba%9b%e8%87%aa%e5%b7%b1%e7%9a%84%e7%90%86%e8%a7%a3%ef%bc%89/

发表回复

(必填)