ArrayList原理

40 阅读2分钟

ArrayList 重点

  • 1.ArrayList中维护了一个Object类型的数组elementData
  • 2.当创建ArrayList对象时,如果使用无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10;如需要再次扩容,则扩容elementData当前容量的1.5倍。
  • 3.如果使用指定大小的构造器,则初始elementData容量为指定的大小,如果需要扩容,则扩容elementData当前容量的1.5倍。
  • 4.扩容时使用Arrays.copyOf(elementData,newCapacity)的方式,保留原有数据的同时增加一些空间。
private void grow(int minCapacity) {
    // overflow-conscious code
    //获取当前容量
    int oldCapacity = elementData.length;
    //获取新的容量(将当前容量的二进制数右移1位后再转为十进制,其实就是当前容量的1.5倍)
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果新容量比指定的容量小
    if (newCapacity - minCapacity < 0)
       //将指定容量作为新容量
        newCapacity = minCapacity;
    //如果新容量比最大数组容量(MAX_ARRAY_SIZE,即2的31次方-9)还要大
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //需要通过hugeCapacity方法进一步确定新容量了,否则新容量依然是当前容量的1.5倍。
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //创建一个类型相同,长度为newLength的数组,并将其返回
    elementData = Arrays.copyOf(elementData, newCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private static int hugeCapacity(int minCapacity) {
  //指定容量小于0,就抛一个内存溢出异常;
  if (minCapacity < 0) // overflow
      throw new OutOfMemoryError();
  //如果指定容量大于最大数组容量(MAX_ARRAY_SIZE,即2的31次方-9),就返回最大的整数2的31次方减一,否则就返回最大数组容量
  return (minCapacity > MAX_ARRAY_SIZE) ?
      Integer.MAX_VALUE :
      MAX_ARRAY_SIZE;
}

拓展问题

  • 为什么最大数组容量要比最大整数相差为8呢?

原因:一些vm在数组中保留了标题。尝试分配较大的数组可能会导致*OutOfMemory错误

  • ArrayList 是线程不安全的,如何再多线程中使用呢?

使用以下方式:
1.List list= Collections.synchronizedList(new ArrayList<>());
2.Vector

  • Collections.synchronizedList和Vector 实现同步的区别?

区别在于:
SynchronizedList使用同步代码块实现同步,锁定的对象为mutex(构造 函数可以传入一个Object,如果在调用的时候显示的传入一个对象,那么锁定的就是用户传入的对象,反之锁定this对象);
Vector使用同步方法实现同步,锁定this对象;

  • 当我们删除元素时,ArrayList 的容量会减少吗?

ArrayList的容量不会减少但是可以使用trimToSize()方法,将ArrayList的容量调整到当前列表的大小,
应用程序可以使用此操作来最小化ArrayList实例的存储。