Iterablejava
集合的最上级接口, 定义了spliterator,iterator和实现了forEach函数
Collection算法
全部集合的父级接口, 定义了通用函数
AbstractCollection数组
实现了Collection中大量函数, 除了特定的几个函数iterator和size以外的函数
AbstractList数据结构
继承了AbstractCollection, 实现了List接口的抽象类, 它实现了List中除size(), get(int location)以外的函数 和AbstractCollection相比, 实现了iterator()接口
RandomAccessdom
提供了随机访问(随机查找)功能, 在ArrayList中经过元素的序号快速获取元素对象, 这就是快速随机访问(随机查找)
Listide
List有序队列接口, 提供了一些经过下标访问元素的函数. List中每个元素都有一个索引, 第一个元素是0, 日后每次+1
ArrayList数据结构是数组 经过必定的算法逻辑动态扩容数组的长度, 能够理解为ArrayList底层是一个动态数组 与java原生的数组相比, 它的容量能动态增加 内存须要连续的空间保证 除去尾部位置元素的添加, 删除操做, 其他都涉及到位置移动 随机查找效率快(下标搜寻)
ArrayList源码设计的优雅之道 new ArrayList的时候, 并不会真的建立长度10的对象数组 何时往里面添加元素了,何时才会完成数组的建立
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; public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
serialVersionUID函数
用来验证版本一致性的字段, 反序列化时会效验
DEFAULT_CAPACITY源码分析
默认容量, 为10
EMPTY_ELEMENTDATA测试
空对象数组
DEFAULTCAPACITY_EMPTY_ELEMENTDATAui
默认容量空对象数组
elementData
动态数组的空间大小, 包含空元素
size
动态数组的实际大小, 记录数组里有多少元素, 不记录空元素
ArrayList()
无参构造 public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;} 把默认容量空对象数组赋值给elementData, 仍是空 无参构造建立动态数组时, size为0, elementData为0
ArrayList(int initialCapacity)
带参构造 参数大于0时 this.elementData = new Object[initialCapacity]; 建立一个大小为initialCapacity的Object数组赋给elementData 参数小与于0时 this.elementData = EMPTY_ELEMENTDATA; 开一个长度为10的空间 参数小与于0时 抛异常
代码测试
public static void main(String[] args) throws Exception { ArrayList arr = new ArrayList(); Field field = arr.getClass().getDeclaredField("elementData"); field.setAccessible(true); Object[] o = (Object[]) field.get(arr); System.out.println(arr.size()); System.out.println(o.length); arr.add("1"); field = arr.getClass().getDeclaredField("elementData"); field.setAccessible(true); o= (Object[]) field.get(arr); System.out.println(arr.size()); System.out.println(o.length); for (int i = 0; i < 16; i++) { arr.add(i); } field = arr.getClass().getDeclaredField("elementData"); field.setAccessible(true); o= (Object[]) field.get(arr); System.out.println(arr.size()); System.out.println(o.length); }
输出
0 0 1 10 17 22
初始化总结
ArrayList arr = new ArrayList(); elementData为0 size为0 ArrayList arr = new ArrayList(1); elementData为0 size为1, 走了带参构造, 参数为几, 空间为几, ArrayList(int initialCapacity) add("test");//添加元素源码分析会讲为何空间为10 elementData为10 size为1 若是第一次添加元素数量为11, 基于动态扩容1.5倍, 它的长度就是15
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
添加一个元素1-10个元素时
add(E e)方法 //以无参初始化(ArrayList arr = new ArrayList();), 并调用add(E e)添加一个元素为例 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } 进ensureCapacityInternal(size + 1);此时传参为1 (0+1=1) private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } 进calculateCapacity, 判断elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA是否成立 public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 条件成立, 由于无参初始化方法已经赋过值 进if, 判断10和参数哪一个大, 10大, 返回10 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } 此时返回ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); 这里, 参数是10 10-10不大于0, 没走到动态扩容 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
目前是elementData(空间长度为10), size为1(size不记录空元素)
添加元素超出10的状况, 动态扩容
添加第11个元素时 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } 此时minCapacity为11 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } 不走if, 返回11, 则ensureExplicitCapacity(11) private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } 11-10大于0, 进入动态扩容 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } 进grow(minCapacity); 动态扩容方法 private void grow(int minCapacity) { 老空间为10 int oldCapacity = elementData.length; 新空间=10+(10>>1), 位运算10的二进制位为1010, 右移动1位二进制为101, 10进制为5, 因此新空间为15=10+5 int newCapacity = oldCapacity + (oldCapacity >> 1); 若是新空间-11小于0,则新空间为11 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; 若是新空间大于0, 则赋值 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //下面讲这个方法 拷贝一个新的数组和长度的集合,赋值给咱们的对象数组 elementData = Arrays.copyOf(elementData, newCapacity); } MAX_ARRAY_SIZE为Integer.MAX_VALUE-8 (int最大值-8) 若是要开的空间大于MAX_ARRAY_SIZE, 就把int最大值-8赋值给它 若是不大于MAX_ARRAY_SIZE,则把MAX_ARRAY_SIZE赋值给它 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } 官方注释对于-8的介绍 这8bit里存了要分配最大数组的大小(数组下标???) 虚拟机中在数据中保留的标题字 (既数组形状判断是否为数组,对象是否同步,数组大小, 不知道是否包含了对象类型的类信息指针???) 尝试分配更大的数组会抛异常, 其实大小仍是支持到了Integer.MAX_VALUE /** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
以前介绍源码的时候把modCount++跳过了, 接下来解释下, 在ArrayList源码里有个监听
源码
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; Itr() {} public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
在每次作集合元素操做时,都会改变modCount,在迭代的时候,会把modCount赋值给expectedModCount, 若是在迭代过程当中删除元素,就会修改modCount,可是迭代器在过程当中不会同步expectedModCount, 每次迭代会会比较是否相等 就是说在使用迭代器的时候, 不能改变元素, 可是能够使用迭代器的方法去改变
public E get(int index) { rangeCheck(index); return elementData(index); } private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } E elementData(int index) { return (E) elementData[index]; }
判断下标是否越界 复杂度O(1), 直接根据下标位置返回元素
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); src - 源数组。 srcPos - 源数组中的起始位置。 dest - 目标数组。 destPos - 目的地数据中的起始位置。 length - 要复制的数组元素的数量。
将指定源数组中的数组从指定位置复制到目标数组的指定位置
好比咱们有个数组 值为 a b c d e f g h i g k 下标 0 1 2 3 4 5 6 7 8 9 10 若是删除f rangeCheck(index); //效验下标越界, index=5 int numMoved = size - index - 1; //numMoved= 4 调用System.arraycopy(elementData, index+1, elementData, index, numMoved);
从原数组下标从6开始copy到新数组从下标从5开始的后面