前言程序员
ArrayList想必是广大Java程序员开发时最经常使用的数据结构了,但不必定对其原理都有了解,今天我将结合ArrayList的源码对其进行讲解。本文将围绕ArrayList主要特性(包括适用场景、初始大小、扩容等)、数据存放方式、核心方法实现、其余特性等四个方面进行讲解。面试
1、ArrayList特性数组
ArrayList是基于数组的数据结构,与LinkedList相比,更加适合在查询多、增删操做少的场景下使用,而且它是非线程安全的,若是并发量比较大的场景,须要改用线程安全的版本或者用JUC包中的CopyOnWriteArrayList。安全
它的初始数组大小为10,由下图所示的成员变量控制:数据结构
当新加元素时原数组已经满了,则会触发扩容,扩容策略为将原数组长度*1.5,代码中是用右移位运算实现的,源码以下所示:多线程
2、数据存放方式并发
ArrayList是以数组的方式存放数据的,Object[],以下所示:this
3、核心方法实现spa
咱们看最经常使用的add方法:线程
1 public boolean add(E e) { 2 ensureCapacityInternal(size + 1); // 若是已经满了,则扩容 3 elementData[size++] = e; 4 return true; 5 }
下面方法用于判断是否原数组已经满了,若是满了则扩容,不满且未初始化则初始化长度为10,不然不用变化
1 private void ensureCapacityInternal(int minCapacity) { 2 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); 3 }
下面方法用于返回数组须要的最小长度。
1 private static int calculateCapacity(Object[] elementData, int minCapacity) { 2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 3 return Math.max(DEFAULT_CAPACITY, minCapacity); 4 } 5 return minCapacity; 6 }
下面的方法用于判断是否须要扩容,若是须要则经过grow方法扩容。
1 private void ensureExplicitCapacity(int minCapacity) { 2 modCount++; 3 4 // overflow-conscious code 5 if (minCapacity - elementData.length > 0) // 若是须要的最小长度大于当前数组总长度,则走grow扩容 6 grow(minCapacity); 7 }
下面的grow方法是控制扩容的核心方法:
1 private void grow(int minCapacity) { 2 // overflow-conscious code 3 int oldCapacity = elementData.length; 4 int newCapacity = oldCapacity + (oldCapacity >> 1); 5 if (newCapacity - minCapacity < 0) // 若是扩容以后的长度小于须要的最小长度,则取最小长度为待扩容长度,这种状况通常不会出现 6 newCapacity = minCapacity; 7 if (newCapacity - MAX_ARRAY_SIZE > 0) 8 newCapacity = hugeCapacity(minCapacity); 9 // minCapacity is usually close to size, so this is a win: 10 elementData = Arrays.copyOf(elementData, newCapacity); // 建立新数组,将老数组的数据复制过去 11 }
注意复制数组时,用的Arrays.copyOf方法,该方法最终引用的是System.arraycopy这个native方法实现的数组复制。其余方法更加简单,此处就不一一粘贴源码解读了。
4、其余特性
一、关于modCount
在看ArrayList源码的时候,会发现有一个变量是modCount,在增删改的方法中均涉及到对它的++操做。modCount属性是在AbstractList中定义出来的:
能够把它理解成每一个ArrayList的一个改动的版本号,只要ArrayList有改动,这个版本号就会+1。在经过迭代器对ArrayList里面的元素进行遍历操做时,每次都会比较一下这个版本号是否有变化,若是检测到预期以外的变化,就会抛出常见的那个异常-ConcurrentModificationException:
ArrayList东西很少,实现也相对比较简单,面试时如今通常会跟Vector或者LinkedList进行比对或者做为多线程的一个引子来问,本文就先到这里,下一期对LinkedList进行解读。