//序列号 private static final long serialVersionUID = 8683452581122892189L; //默认初始容量 10 private static final int DEFAULT_CAPACITY = 10; //一个空数组,当用户指定ArrayList容量为0时,用户指定容量为 0 时返回返回该数组 //ArrayList list1 = new ArrayList(0); private static final Object[] EMPTY_ELEMENTDATA = {}; //ArrayList list = new ArrayList(); //1. 当用户没有指定 ArrayList() 的容量时(即调用无参构造函数),返回的是该数组==>刚创建一个 ArrayList 时,其内数据量为 0。 //2. 当用户第一次添加元素时,该数组将会扩容,变成默认容量为 10(DEFAULT_CAPACITY) 的一个数组===>通过 ensureCapacityInternal() 实现 //3. 它与 EMPTY_ELEMENTDATA 的区别就是:该数组是默认返回的,而后者是在用户指定容量为 0 时返回 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //1. 当前数据对象存放地方,当前对象不参与序列化 //2. 这个关键字最主要的作用就是当序列化时,被transient修饰的内容将不会被序列化 transient Object[] elementData; //ArrayList实际存储的数据数量 private int size; //继承于AbstractList //集合数组修改次数的标识 protected transient int modCount = 0;
无参构造方法_(DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
//1. 无参构造函数:没有进行传参 当前元素数组直接返回默认 容量空元素数据 DEFAULTCAPACITY_EMPTY_ELEMENTDATA //2. 创建一个 空的 ArrayList,此时其内数组缓冲区 elementData = {}, 长度为 0 //3. 当元素第一次被加入时,扩容至默认容量 10 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
有参构造方法1,若参数为0_EMPTY_(ELEMENTDATA)
/** * @param initialCapacity 初始容量 * @throws IllegalArgumentException 当初试容量值非法(小于0)时抛出 */ //创建一个初试容量的、空的ArrayList arraylist并不是懒加载机制 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // 当出现这个情况 ArrayList list = new ArrayList(0);和直接不传是不一样的 //传0 是直接赋值 EMPTY_ELEMENTDATA //不传 是直接赋值 DEFAULTCAPACITY_EMPTY_ELEMENTDATA //初始化容量为0 的时候 直接返回 EMPTY_ELEMENTDATA 空元素数据 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
有参构造方法2_集合添加
/** * @param c 要放入 ArrayList 中的集合,其内元素将会全部添加到新建的 ArrayList 实例中 * @throws NullPointerException 当参数 c 为 null 时抛出异常 */ //创建一个包含collection的ArrayList public ArrayList(Collection<? extends E> c) { //把集合传化成Object[]数组 elementData = c.toArray(); //转化后的数组长度赋给当前ArrayList的size,并判断是否为0 if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) // 若c.toArray() 返回的数组类型不是 Object[],则利用 Arrays.copyOf(); 来构造一个大小为 size 的 Object[] 数组 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 数组长度为0 直接使用空数组 this.elementData = EMPTY_ELEMENTDATA; } }
1. add(E e) 默认直接在末尾添加元素
//增加指定的元素到ArrayList的最后位置 public boolean add(E e) { //确定ArrayList的容量大小 size是当前集合元素的个数 // 若第一次 size肯定是0 minCapacity=1 +1是未来判断新加进来的元素是否有位置可以存下来 ensureCapacityInternal(size + 1); //确保容量充足 进行元素添加 elementData[size++] = e; return true; }
2. ensureCapacityInternal(size + 1) 确定内部容量的方法
//确保内部容量 private void ensureCapacityInternal(int minCapacity) { //calculateCapacity()判断是否走的是空参构造函数 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 将容量初始为10 //ensureExplicitCapacity判断容量是否要进行扩容 并且modCount++ ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
3. calculateCapacity()判断是否走的是空参构造函数,走空参将容量初始为10
//DEFAULTCAPACITY_EMPTY_ELEMENTDATA 主要是这个 默认容量空元素数据 //这个返回主要是看list是不是初始的时候是调用的空参构造函数 ====>ArrayList list = new ArrayList(); DEFAULTCAPACITY_EMPTY_ELEMENTDATA private static int calculateCapacity(Object[] elementData, int minCapacity) { //如果没有指定初始化容量,第一次调用add()方法,会初始化容量为10 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //直接返回minCapacity默认容量10 和传入的最小容量取最大值 return Math.max(DEFAULT_CAPACITY, minCapacity); } //若不是第一次添加直接返回minCapacity 也就是数组的大小+1 return minCapacity; }
4.还是确保明确的容量 ensureExplicitCapacity(int minCapacity)
//还是确保明确的容量 private void ensureExplicitCapacity(int minCapacity) { // 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的 modCount++; // 防止溢出代码:确保指定的最小容量 > 数组缓冲区当前的长度 //若当前集合的最小容量超过数据的长度 需要进行扩容 //比如第一次添加&&elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA ==> minCapacity=10 if (minCapacity - elementData.length > 0) grow(minCapacity); }
5. grow(int minCapacity) 扩容机制——重点
//扩容,以确保 ArrayList 至少能存储 minCapacity 个元素 private void grow(int minCapacity) { // 计算出老的数组的容量 int oldCapacity = elementData.length; //扩充当前容量为老的数组容量1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); // 若扩充后newCapacity 还是小于 添加元素时候传进来的容量 minCapacity if (newCapacity - minCapacity < 0) //直接将minCapacity直接赋值新的容量 newCapacity //若是第一次 newCapacity = minCapacity=10 newCapacity = minCapacity; // 若扩充后的newCapacity 大于最大存储容量,则进行大容量分配 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //将数组元素进行copy 长度为 newCapacity elementData = Arrays.copyOf(elementData, newCapacity); }
6.hugeCapacity()大容量分配,最大分配 Integer.MAX_VALUE
/** * 数组缓冲区最大存储容量 * - 一些 VM 会在一个数组中存储某些数据--->为什么要减去 8 的原因 * - 尝试分配这个最大存储容量,可能会导致 OutOfMemoryError(当该值 > VM 的限制时) */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //大容量分配,最大分配 Integer.MAX_VALUE private static int hugeCapacity(int minCapacity) { //越界直接抛异常 if (minCapacity < 0) throw new OutOfMemoryError(); //Integer.MAX_VALUE - 8; return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
7.分析一波ArrayList构造函数不传容量的情况
//1. 不传容量参数,直接走空参构造方法 List<Integer> lists = new ArrayList<Integer>(); lists.add(8); //2. 走空参构造函数 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //3. 添加元素的时候 进行判断==>空参直接使用默认容量10 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //直接返回minCapacity默认容量10 和传入的最小容量取最大值 return Math.max(DEFAULT_CAPACITY, minCapacity); }
8.分析一波ArrayList构造函数传一个容量的情况或者传0情况
//1. 传一个初始化容量参数6 List<Integer> lists = new ArrayList<Integer>(6); lists.add(8); //2. 创建一个初试容量的、空的ArrayList arraylist并不是懒加载机制 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //大于0 直接创建一个对象数组 this.elementData = new Object[initialCapacity]; //传0 是直接赋值 EMPTY_ELEMENTDATA } else if (initialCapacity == 0) { // 当出现这个情况 ArrayList list = new ArrayList(0);和直接不传是不一样的 //传0 是直接赋值 EMPTY_ELEMENTDATA //不传 是直接赋值 DEFAULTCAPACITY_EMPTY_ELEMENTDATA //初始化容量为0 的时候 直接返回 EMPTY_ELEMENTDATA 空元素数据 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
9.remove(int index) 移除指定位置下标的元素
//移除指定位置下标的元素 public E remove(int index) { //1. 判断索引是否越界 rangeCheck(index); //2. 增加修改的次数 modCount++; //3. 保存要删除的元素为oldValue E oldValue = elementData(index); //4. 将指定位置index+1往后的元素都向前移动一位,覆盖需要删除的元素 int numMoved = size - index - 1; // 再进行数组copy if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); // 将最后一个元素置空 elementData[--size] = null; // 返回删除的元素 return oldValue; }
10.remove(Object o) 移除list中指定的第一个元素
//移除list中指定的第一个元素 public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { //如果包含null这个元素,index 之后的所有元素依次左移一位 fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) //通过元素 计算出下标 if (o.equals(elementData[index])) { //如果包含这个元素,index 之后的所有元素依次左移一位 fastRemove(index); return true; } } return false; }
11.fastRemove(int index) 传入下标进行删除当前index下标位置的元素
//传入下标进行删除当前index下标位置的元素 private void fastRemove(int index) { modCount++; //移动的个数 int numMoved = size - index - 1; //将index后面的元素移动前面来 index位置的元素就是在最后一个位置 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //将最后一个元素删除 elementData[--size] = null; }
12.get(int index) 直接获取下标的位置的值
//直接获取下标的位置的值 public E get(int index) { //检查范围 rangeCheck(index); //直接返回 return elementData(index); }
13.clear 将elementData中每个元素都赋值为null,等待垃圾回收将这个给回收掉
//移除list中的所有元素,这个list表将在调用之后置空 public void clear() { modCount++; for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
补充一个添加元素add整个的流程
补充一个删除元素remove整个的流程