ArrayList的扩容


最近把数据结构的链表复习了一遍,感觉就是在刨jdk里的源码.链表的实现和ArrayList 底层都是用数组来实现,

基本的方法实现都非常相似,ArrayList 随着jdk的升级多了一些信新的特性。重点还是来看看里面的扩容是怎么来实现的?

ArrayList 共实现三个接口,RandomAccess,Cloneable,Serializable,继承 AbstractList类。

  /**
     序列化
    */
 private static final long serialVersionUID = 8683452581122892189L;

/**
*  默认初始化容量大小
*/
private static final int DEFAULT_CAPACITY = 10;

/**
 *  定义一个空数组
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 *  默认的空数组
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 *   实际存储的数组
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
    数组实际大小
 */
private int size;

ArraList的构造函数

  1. ArrayList(int initialCapacity) 如果初始值大于0则新建一个大小为initialCapacity 的数组赋值给当前实际存储的数组

如果 initialCapacity 初始值等于0 则当前实际存储的数组设为空数组,

如果初始值小于则这直接抛出异常

  1. 无惨构造函数,直接默认的空数组赋值给当前的实际数组

  2. 就是参数为 Collection 的构造函数,可以存放实现 Collection 接口下的 list ,set 等

到这里似乎还没看到跟ArrayList的扩容相关的,看看他的add方法是如何来实现的


/**
   * Appends the specified element to the end of this list.
   *
   * @param e element to be appended to this list
   * @return <tt>true</tt> (as specified by {@link Collection#add})
   */
  public boolean add(E e) {
      ensureCapacityInternal(size + 1);  // Increments modCount!!
      elementData[size++] = e;
      return true;
  }

将元素e赋值之前 ensureCapacityInternal(size+1) 操作,重点来关注该系列方法

**关于安全扩容共有3个方法 **

  1. ensureCapacity(int minCapacity) 获取最小延伸值 minExpand ,比较最小延伸值与最小初始值大小从而来执行

ensureExplicitCapacity(minCapacity) 方法

  1. ensureCapacityInternal(int minCapacity) 方法,先判断 当前数组与默认的空数组是否相等,若成立 则最小初始化值为

默认值与原最小初始化值二者之间的最大值。 最后调用 ensureExplicitCapacity(minCapacity) 该方法

  1. ensureExplicitCapacity(int minCapacity), modeCount 是在 AbstractList 抽象类里面定义的

protected transient int modCount = 0; transient 关键字 序列化对象的时候,这个属性就不会序列化到指定的目的地中

判断是否扩容的关键就在 if语句里面 ,if(minCapacity - elementData.length > 0) 就是最小初始化值大于当前实际存储数组的值,则调用grow(minCapacity) 方法

判断是否扩容的关键就是 最小初始值大于当前实际存储数组的长度

ArrayList的扩容 grow(minCapacity)

/**
  *  grow() 方法是ArrayList扩容的关键
      右移一位相当于除2,右移n位相当于除以2的n次方。
      如果 oldCapacity =11 ,则  (oldCapacity >> 1) 结果就是5
      关于位移运算,可以下去研究一下
  */
 private void grow(int minCapacity) {
     // overflow-conscious code
      //  原容量等于当前数组的长度
     int oldCapacity = elementData.length;
      // 新的容量等于原始容量+原始容量右移一位
     int newCapacity = oldCapacity + (oldCapacity >> 1);
      //   如果新的初始容量减去最小容量小于0 则新容量等最小初始容量
     if (newCapacity - minCapacity < 0)
         newCapacity = minCapacity;
         // 如果新容量减去最大数组值大于0则新的容量则新容量等于Integer.MAX_VALUE 或者MAX_ARRAY_SIZE
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         newCapacity = hugeCapacity(minCapacity);
     // minCapacity is usually close to size, so this is a win:

      // 然后copy一份之前的数组和最新的容量赋值给之前数组
     elementData = Arrays.copyOf(elementData, newCapacity);
 }

ArrayList的新容量是原容量右移一位加上原容量值,看完源码后试图自己写一个ArrayList集合。


文章作者: coderpwh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 coderpwh !
  目录