ArrayList
由于ArrayList的数据结构是基于数组的形式所以在查找、修改和尾部添加方面很快,但删除和指定位置添加速度比较慢
首先看ArraysList的全局变量如下:
//继承了抽象AbstractList和随机访问的接口RandomAccess和克隆、序列化接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* 初始化默认容量为10;
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 创建空对象数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 创建一个使用默认容量的空对象数组(无参构造的时候使用)
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
*存储Arraylist元素的数组,在添加第一个元素的时候,缓冲数组会扩展为默认初始化容量大小
*而且该数组是transient标记,是无法序列化的
*/
transient Object[] elementData;
/**
*Arraylist元素的数量
*
* @serial
*/
private int size;
构造方法的分析:
-
构建的时候带容量的构造方法
/** * * @param initialCapacity 是创建arraylist的容量 * @throws 当initialCapacity小于0 则抛出一个参数非法异常 */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //为elementData创建一个容量为initialCapacity的对象数组, this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //如果是0则使用默认的空数组 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * 无参构造函数 *直接把全局的使用默认容量的对象数组给elementData */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
-
带有集合元素的构造方法
特别注意toArray这里有个调用问题(如果是相同类型就会以为方法还没返回elementData就已经有需要添加的数据的错觉,因为调用的是同一份源码)/** * 带有集合元素的构造方法 * @param c 是一个带有元素的Collection实例 * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { //1.c通过调用Arrays这个类的方法 先把c的collection对象转换为一个对象数组并暂时赋值给elementData; elementData = c.toArray(); //2.把这个元素数组的长度赋值个size并判断 //2.1 size!=0的情况 if ((size = elementData.length) != 0) { //判断elementData数组的类目是否是Object //如果不是则调用Arrays这个类进行转换为Object这种类型的数组并重新赋值个elementData这个数组 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { //2.2 如果等于0则使用全局的空对象数组赋予elementData. this.elementData = EMPTY_ELEMENTDATA; } } //1.2 这个方法的作用是放回调用者的数据对象数组,这个方法是c.集合调用的,所以Arrays.copyOf(elementData, size);中的elementData是c这个集合对象的元素数组(注:通过debug可以清楚看到(因为这个是c调用,这里有个域问题,因为用如果两个都是ArrayList会出现混淆,建议使用LinkedList作为参数进行构建,然后debug会很清晰)) public Object[] toArray() { return Arrays.copyOf(elementData, size); }
**trimToSize()**这个方法是通过去空来调整当前ArrayList的大小
public void trimToSize() { //modCount这个变量是Arraylist集成AbstractList这个类里面的一个迭代器类的变量,该变量是记录操作次数,它的作用相当于一个基于版本号的乐观锁,每次进行修改操作记录一次,并把这个值赋予一个期望变量 int expectedModCount = modCount;,在进行迭代器迭代遍历的时候如果期望值和当前modeCount值不同时则不能进行迭代遍历,抛出一个并发异常 modCount++; //2.如果当前元素个数小于 元素数组的长度(构建的时候的容量) if (size < elementData.length) { //如果sizet=0则赋值全局的空对象数组 //否则则通过Arrays调用copyOf方法,以当前数据个数size作为新数组的大小重新构建一个包含原来全部数据的数组返回。 elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } } //Arrays.copyOf()方法实现过程: //original是原带有数据的elementData元素数组,newLength是实际元素的个数 public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); } //original.getClass()获取原数组的类名 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") //根据原数组的类型和newLength创建一个数组 T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); //进行数据拷贝 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
-
ArrayList的扩容
ArrayList每次进行add操作的时候会进行一次判断,如果容量不族则调用grow()进行扩容,默认每次扩容是数据个数size+1,此外,我们也可以通过调用void ensureCapacity(int minCapacity)进行扩容,传入一个数组,该方法进行判断如果这个数值大于elementData数组长度而且该数组不是默认初始化大小的空对象数组和这个数组小于默认容量的时候才进行扩容
public void ensureCapacity(int minCapacity) { //进行判断传入的数值是否但与数据数组长度和这个数组是否是默认初始化空对象数组 if (minCapacity > elementData.length && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA && minCapacity <= DEFAULT_CAPACITY)) { modCount++; grow(minCapacity); } } //数组的最大容量是-8 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //通过Array.copyOf进行数组扩容,先通过newCapacity进行比较需要扩容的数值是否超过了数组的最大容量 private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); } private Object[] grow() { return grow(size + 1); } //判断扩展数值 private int newCapacity(int minCapacity) { // overflow-conscious code //先拿到原elelementData元素数组的长度 int oldCapacity = elementData.length; //新数组的长度等于旧数组的容量的二分之三倍(1.5倍) int newCapacity = oldCapacity + (oldCapacity >> 1); //如果新容量小于需要扩容的容量值minCapacity,则进行一次数组选择 if (newCapacity - minCapacity <= 0) { //如果elementData等于初始化对象数组则返回ArrayList的默认初始化容量和minCapactiy这两者的较大者。 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) return Math.max(DEFAULT_CAPACITY, minCapacity); //如果小于0爆内存溢出 if (minCapacity < 0) // overflow throw new OutOfMemoryError(); 否则返回 return minCapacity; } //如果新的容量小于最大值则返回新容量,else,通过hugeCapacity对ch传入的数值再次进行比较返回一个最大值。 return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
-
ArrayList中的HasCode
/** * {@inheritDoc} */ public int hashCode() { //在计算一个ArrayList实例的哈希码前先记录当前操作次数作为一个期望值 int expectedModCount = modCount; //调用方法生成哈希码 int hash = hashCodeRange(0, size); //再次判断是否符合预期否则抛异常 checkForComodification(expectedModCount); //返回哈希码 return hash; } int hashCodeRange(int from, int to) { final Object[] es = elementData; //如果size大于元素数组的长度抛并发异常 if (to > es.length) { throw new ConcurrentModificationException(); } //初始化hashCode=1 int hashCode = 1; //遍历每个元素,而且每次hascode的值等于 前一个hashcod*31+当前元素的哈希码(例如整数的哈希码是它的数值) for (int i = from; i < to; i++) { Object e = es[i]; hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); } return hashCode; }
-
ArrayList的equals
public boolean equals(Object o) { //是否是当前对象 if (o == this) { return true; } //判断类型是否是list类型 if (!(o instanceof List)) { return false; } //同样记录期望值 final int expectedModCount = modCount; //判断当前值否符是通一个类型,来进行不同的判断 boolean equal = (o.getClass() == ArrayList.class) ? equalsArrayList((ArrayList<?>) o) : equalsRange((List<?>) o, 0, size); checkForComodification(expectedModCount); return equal; } boolean equalsRange(List<?> other, int from, int to) { final Object[] es = elementData; if (to > es.length) { throw new ConcurrentModificationException(); } //获取目标集合的迭代器,通过迭代元素比较 var oit = other.iterator(); for (; from < to; from++) { if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) { return false; } } return !oit.hasNext(); } //如果是Arraylist则跳到这个判断方法 private boolean equalsArrayList(ArrayList<?> other) { //期望值 final int otherModCount = other.modCount; final int s = size; boolean equal; if (equal = (s == other.size)) { final Object[] otherEs = other.elementData; final Object[] es = elementData; //如果当前Arrayslist的数据大小超过长度则爆并发异常 if (s > es.length || s > otherEs.length) { throw new ConcurrentModificationException(); } //遍历比较 for (int i = 0; i < s; i++) { if (!Objects.equals(es[i], otherEs[i])) { equal = false; break; } } } //再次判断 other.checkForComodification(otherModCount); return equal; }
-
获取ArrayList的大小和判空
public int size() { return size; } public boolean isEmpty() { return size == 0; }
常用的方法分析‘
-
//通过调用indexof获取o对象的位置,进行判断并返回 public boolean contains(Object o) { return indexOf(o) >= 0; } //获取第一个对象o的下标(该方法和获取最后一个出现对象的下标实现类似,只是倒着遍历) public int indexOf(Object o) { //通过indexofRange,从0开始到size进行数组 遍历 return indexOfRange(o, 0, size); } //对elementData进行遍历查找数值相等的元素下标并返回 int indexOfRange(Object o, int start, int end) { Object[] es = elementData; if (o == null) { for (int i = start; i < end; i++) { if (es[i] == null) { return i; } } } else { for (int i = start; i < end; i++) { if (o.equals(es[i])) { return i; } } } return -1; }
ArrayList的克隆/拷贝
首先我们要知道拷贝有浅拷贝和深拷贝
- 浅拷贝:对于基本类型进行值传递,对引用数据类型禁止引用传递的拷贝(即对引用类型不进行创建对象,指是对该对象的地址引用)----为浅拷贝
- 深拷贝:对于基本数据类型进行值传递,对于引用类型,创建一个新的对象,并且复制其内容–深拷贝
-
public Object clone() { try { //先拷贝基本类型 ArrayList<?> v = (ArrayList<?>) super.clone(); 对于引用类型通过Arrays.copyof拷贝一份并赋值给v的elementData数组 v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } }
获取一个数据数组
//传入一个数组,并把ArrayList的数据赋值到该数组中,然后返回 public <T> T[] toArray(T[] a) { //如果传入的数组长度小于size则通过Arrays.copyOf进行拷贝返回一个大小为size,类型是a.getClass类型的数组并返回 if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); //如果a数组长度大于size则直接通过底层拷贝 System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } //该方法也是获取一个数据数组 public Object[] toArray() { return Arrays.copyOf(elementData, size); }
-
根据下标获取一个数据
//先需要获取元素的下标和数据大小size进行比较,如果超出了则抛异常 public E get(int index) { //对下标进行检查 Objects.checkIndex(index, size); //如果正常则直接根据下标在elementData获取数据 return elementData(index); } //对下标进行检查的过程: 1.Objects调用检查方法,然后底层通过 Preconditions.checkIndex进行实际的检查 public static int checkIndex(int index, int length) { return Preconditions.checkIndex(index, length, null); } //真正进行下标检查的方法 public static <X extends RuntimeException>int checkIndex(int index, int length, BiFunction<String, List<Integer>, X> oobef) { //如果小于0或者大于size就抛越界 if (index < 0 || index >= length) throw outOfBoundsCheckIndex(oobef, index, length); return index; }
-
根据下标修改数据
//与get方法一样先进行下标校验,如果正常就获取该下标的元素赋值给oldValue,然后把当前下标的elementData数据换成要修改的数据 public E set(int index, E element) { Objects.checkIndex(index, size); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
-
ArrayList的迭代器,为了方便遍历ArrayList采用了迭代器模式
在分析迭代器之前先分析一下前面提到的modCount这个变量,该变量是每次Arraylist进行updat(修改,删除,添加的时候都会出现) modCount+1这个前面已经有分析了,是对集合迭代时进行是否存在并发判断,多个线程操作时,一条线程进行add添加元素,一条线程进行迭代输出时,这个标记就可以记录刚刚开始迭代时总共操作修改次数的modCount,然后每次next一个元素进行一次比较modCount和刚刚开始迭代的时候的预期是否相同,如果不同证明已经有线程修改了,则抛并发异常。
itr这个类是ArrayList的内部类专业用来返回一个ArrayList的迭代器,它功能是迭代读取数据和移除数据//该方法是ArrayList向外界提供获取迭代器的方法 public Iterator<E> iterator() { return new Itr(); } //这个类是实际获取迭代器的内部类 private class Itr implements Iterator<E> { //相当于数据库的游标,每次next一次就+1 int cursor = 0; /** *该变量是记录每次通过next获取一个元素的元素下标,并且每次删除一个元素则重置为-1 */ int lastRet = -1; /** *每次获取一个迭代器的时候先把当前操作次数赋予该期望变量 */ int expectedModCount = modCount; //判断是否有还有值 public boolean hasNext() { return cursor != size(); } public E next() { //进行next前进行 比较操作数和预期操作数是否一致,如果不一致抛并发异常(相当于一个版本号乐观锁) checkForComodification(); try { //正常获取数据,每次获取一个把lastRet置为该元素下标,curso游标等于该下标+1好为获取下一个元素做判断 int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } //移除操作,如果lastRet<0则证明没有元素 public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { //移除lastRet AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } //检查期望值和当前操作值是否一致,如果不一致证明被其他线程修改了 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
- 获取ListItr迭代器,该迭代器是itr这个类的加强版,同时他也是ArrayList的子类,除了顺序迭代功能还可以逆序迭代,从当前游标反向迭代、添加元素、修改元素。
//返回一个指定下标开始的迭代器 public ListIterator<E> listIterator(int index) { rangeCheckForAdd(index); return new ListItr(index); } /** *返回一个listIterator迭代器 */ public ListIterator<E> listIterator() { return new ListItr(0); } private class ListItr extends Itr implements ListIterator<E> { //迭代指定下标开始的迭代器idnex赋值个游标cursor ListItr(int index) { super(); cursor = index; } public boolean hasPrevious() { return cursor != 0; } public int nextIndex() { return cursor; } //获取前一个下标index public int previousIndex() { return cursor - 1; } @SuppressWarnings("unchecked") public E previous() { //判断预期是否和当前一致 checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; //返回前一个元素 return (E) elementData[lastRet = i]; } // 修改和添加都差不多 public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
-
ArrayList获取一个子序列
//传入指定下标,返回一个子序列 public List<E> subList(int fromIndex, int toIndex) { //越界判断 subListRangeCheck(fromIndex, toIndex, size); return new SubList<>(this, fromIndex, toIndex); } //该类是ArrayList的一个内部类,具体方法实现基本都是调用ArrayList的方法 private static class SubList<E> extends AbstractList<E> implements RandomAccess { private final ArrayList<E> root; private final SubList<E> parent; private final int offset; private int size; }
-
添加一个元素add方法,这个方法有多个重载,但对外只提供两个使用,其他作为辅助方法
/** *该方法是提供外界进行添加的,每次进行添加的时候modCount会进行+1,这是为了Arraylist进行迭代使用的,后面会进行分析(每次进行set/add/remove都会进行+1) public boolean add(E e) { modCount++; //调用辅助方法 add(e, elementData, size); return true; } /** * 这个方法是一个辅助方法帮助add方法进行元素添加 */ private void add(E e, Object[] elementData, int s) { //判断是否需要扩容 if (s == elementData.length) elementData = grow(); //在末尾进行添加 elementData[s] = e; size = s + 1; } /** * 在指定下标添加一个元素,如果该下标元素存在则该下标一直到size为下标的元素全部后移一位腾出该下标的位置插入元素(ArrayList数据结构是数组所以指定位置速度较慢) */ public void add(int index, E element) { //判断是否越界 rangeCheckForAdd(index); modCount++; final int s; Object[] elementData; //判断当前数据个数size和数组长度是否相等来判断是否需要扩容 if ((s = size) == (elementData = this.elementData).length) elementData = grow(); //否则则直接通系统的system进行数据拷贝的形式添加,拷贝过程是,elementData数组的idex下标的元素拷贝到 elementData数组的idex+1开始覆盖,一直拷贝s-index个(拷贝的长度)这样就可以把idex空出来。其中第一个elementData是源数组,elementData是目标数组,index是源数组开始拷贝的位置,index+numNew是从源数组拷贝的元素存放在目标数组的位置下标,numMoved是拷贝的长度 System.arraycopy(elementData, index, elementData, index + 1, s - index); //这里进行对index赋值 elementData[index] = element; size = s + 1; } //该方法是add内部进行判断是否越界 private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
-
批量添加addAll,批量添加分两种一直尾部添加,一种指定添加,都这些都是通过系统类底层数组拷贝来实现
//该方法是尾部添加 public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); modCount++; //如果a长度为0直接返回 int numNew = a.length; if (numNew == 0) return false; Object[] elementData; final int s; //判断是否需要进行扩容数组 if (numNew > (elementData = this.elementData).length - (s = size)) elementData = grow(s + numNew); 通过系统类底层进行数组拷贝,把a数组下标0的元素开始拷贝到elementData数组的下标为s一直到s+numNew ,numNew是拷贝的个数 System.arraycopy(a, 0, elementData, s, numNew); //修改实际数据的大小 size = s + numNew; return true; } /** *指定位置开始插入 */ public boolean addAll(int index, Collection<? extends E> c) { //检查越界 rangeCheckForAdd(index); Object[] a = c.toArray(); modCount++; int numNew = a.length; if (numNew == 0) return false; Object[] elementData; final int s; //空闲位置大小小于numNew则扩容 if (numNew > (elementData = this.elementData).length - (s = size)) elementData = grow(s + numNew); //以上和上面基本一样 //numMoved是需要从index开始需要移动多少个元素,如果不大于0则直接直接拷贝就可以了 int numMoved = s - index; if (numMoved > 0) //拷贝过程是从elementData下标为index开始拷贝到 elementData数组的index+numNew下标开始一直到index+numNex+numMoved,其中第一个elementData是源数组,elementData是目标数组,index是源数组开始拷贝的位置,index+numNew是从源数组拷贝的元素存放在目标数组的位置下标,numMoved是拷贝的长度 System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //然后再次拷贝把a数组数据填充到刚刚空出来的位置 System.arraycopy(a, 0, elementData, index, numNew); size = s + numNew; return true; }
-
移除元素/清除数据
public E remove(int index) { //越界检查 Objects.checkIndex(index, size); final Object[] es = elementData; //获取删除的值 @SuppressWarnings("unchecked") E oldValue = (E) es[index]; fastRemove(es, index); //返回删除的值 return oldValue; } //真正进行删除的方法 private void fastRemove(Object[] es, int i) { modCount++; final int newSize; if ((newSize = size - 1) > i) //也是通过系统类进行数组拷贝,es源素组,源素组下标i+1的位置开始,es是作为目标数组,i是目标数组开始拷贝覆盖的开始下标,newSize-i是赋值长度,即从i+1~~newSize-i长度的元素拷贝到目标数组的i下标直到后面。 System.arraycopy(es, i + 1, es, i, newSize - i); //然后把该size置为0 es[size = newSize] = null; } //指定范围删除 protected void removeRange(int fromIndex, int toIndex) { //判断是否越界 if (fromIndex > toIndex) { throw new IndexOutOfBoundsException( outOfBoundsMsg(fromIndex, toIndex)); } modCount++; //调用移除方法 shiftTailOverGap(elementData, fromIndex, toIndex); } //实际移除的方法 private void shiftTailOverGap(Object[] es, int lo, int hi) { //系统拷贝和上面分析一样 System.arraycopy(es, hi, es, lo, size - hi); for (int to = size, i = (size -= hi - lo); i < to; i++) es[i] = null; } //通过遍历置空把清除数据 public void clear() { modCount++; final Object[] es = elementData; for (int to = size, i = size = 0; i < to; i++) es[i] = null; }
-
移除包含集合的所有数据/移除集合不包含的所有数据。。
jdk 11.6 中删除包含不包含元素过程图
java 1.8的删除包含的元素的流程图(不包含的也是这个图)
```
//移除所有c包含的数据
public boolean removeAll(Collection<?> c) {
//调用移除方法
return batchRemove(c, false, 0, size);
}
/**
*移除c不包含的所有数据
*/
public boolean retainAll(Collection<?> c) {
return batchRemove(c, true, 0, size);
}
//jdk 11.6 complement: true :移除c不包含的数据 ,否则移除c包含的数据。
boolean batchRemove(Collection<?> c, boolean complement,
final int from, final int end) {
//判断是否是空
Objects.requireNonNull(c);
final Object[] es = elementData;
int r;
r=0 ;
//循环遍历找到第一个不不包含或者包含的元素然后break记录该坐标
for (r = from;; r++) {
if (r == end)
return false;
if (c.contains(es[r]) != complement)
break;
}
//把r赋值给w
int w = r++;
try {
//再次遍历,从第一个不符合元素下标开始 一直找到包含或者不包含的元素然后覆盖掉
for (Object e; r < end; r++)
if (c.contains(e = es[r]) == complement)
es[w++] = e;
} catch (Throwable ex) {
System.arraycopy(es, r, es, w, end - r);
w += end - r;
throw ex;
} finally {
//调用范围移除方法进行移除 同时记录操作次数
modCount += end - w;
shiftTailOverGap(es, w, end);
}
return true;
}
//jdk1.8
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
//该流程可以看上图
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// 将elementData中下标为r开始右边的值拷贝到elementData中下标为w开始覆盖,size-r是覆盖的长度(或者个数)
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
/修改w的值
w += size - r;
}
//从w开始置空
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
```
-
ArrayList序列化对象和反序列化对象
//根据传入的对象输出流把elementData的对象进行序列化 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // 序列化开始前记录当前操作数作为一个期望值 int expectedModCount = modCount; s.defaultWriteObject(); // 把数据大小写入 s.writeInt(size); // 遍历写数组中的元素 for (int i=0; i<size; i++) { s.writeObject(elementData[i]); } //最后进行当前操作数和期望值进行比较如果不相等则抛并发异常 if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } /** * */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // 读取对象 s.defaultReadObject(); // Read in capacity 读取容量 s.readInt(); // ignored if (size > 0) { // like clone(), allocate array based upon size not capacity SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size); Object[] elements = new Object[size]; //遍历读取对象存入elements中 for (int i = 0; i < size; i++) { elements[i] = s.readObject(); } //把elements赋值给elementData elementData = elements; } else if (size == 0) { //如果size=0则使用默认空对象数组赋值 elementData = EMPTY_ELEMENTDATA; } else { throw new java.io.InvalidObjectException("Invalid size: " + size); } }
总结:Arraylist是内部是基于对象数组实现,通过维持一个modCount来保证在迭代器的情况、和equeal时不会同时存在多个线程操作,否则会爆一个并发异常,也说明ArrayLIst不支持并发情况的,除此之外ArrayList的添加删除修改操作,实际生是通过系统System底层类通过数组拷贝实现的. (ArrayList在jdk11和jdk8好像只优化了很少一部分,可能底层优化了吧)
HashTable源码分析
LinkedList源码分析
Vector源码分析
CopyOnWriteArrayList源码分析
SynchorincedList源码分析