ArrayList

官方文档

  1. 是List接口的可调整大小的数组实现,并且提供了直接更改底层数据大小的方法
  1. size,isEmpty,get,set,iterator,listIterator方法时间复杂度为O(1), add方法的时间复杂度为O(n)
notion image

结构

类图

notion image
通过实现AbstractList获得了List接口的所有属性和方法
RandomAccess 集合框架的标记接口,代表实现这个接口的容器支持快速访问,并且用普通for循环迭代快于迭代器和增强for循环
notion image

成员变量

notion image

elementData

存储元素的数组缓冲区,数组长度即ArrayList的容量
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access
通过文档注释,当我们new 一个 new ArrayList()的时候,elementData初始化一个空的数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
notion image
当第一个元素被添加的时候会扩容到初始化容量DEFAULT_CAPACITY
notion image

modCount

支持快速失败机制,
notion image

构造函数

/** * 构造一个指定容量的空集合 * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ 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); } } /** * Constructs an empty list with an initial capacity of ten. * 构造一个初始容量的空数组,在第一个元素添加的时候才会真正扩容 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. 传入一个collection实现,构造一个新的包含这个实现所有元素的集合 * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { Object[] a = c.toArray(); if ((size = a.length) != 0) { if (c.getClass() == ArrayList.class) { elementData = a; } else { elementData = Arrays.copyOf(a, size, Object[].class); } } else { // replace with empty array. elementData = EMPTY_ELEMENTDATA; } }

成员方法

主要看crud方法

get( int index )

/** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { Objects.checkIndex(index, size); return elementData(index); }

set(int index, E element)

/** * Replaces the element at the specified position in this list with * the specified element. * * @param index index of the element to replace * @param element element to be stored at the specified position * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { Objects.checkIndex(index, size); E oldValue = elementData(index); elementData[index] = element; return oldValue; }

boolean add(E e)

/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { modCount++; add(e, elementData, size); return true; } /** * This helper method split out from add(E) to keep method * bytecode size under 35 (the -XX:MaxInlineSize default value), * which helps when add(E) is called in a C1-compiled loop. */ private void add(E e, Object[] elementData, int s) { if (s == elementData.length)//判断size是不是等于数组元素长度 elementData = grow();//进行扩容 elementData[s] = e; size = s + 1; }

扩容机制

  1. 判断list不是无参构造new出来的list (底层为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  1. 如果是DEFAULTCAPACITY_EMPTY_ELEMENTDATA 类型的空List,list底层数组赋值为一个新数组,新数组的长度为 默认值为 max(DEFAULT_CAPACITY, minCapacity) ,其实就是DEFAULT_CAPACITY 10
  1. 不是默认的空List,重新计算扩容后的新容量值
private Object[] grow() { return grow(size + 1); } /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity * @throws OutOfMemoryError if minCapacity is less than zero */ private Object[] grow(int minCapacity) { int oldCapacity = elementData.length; if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { int newCapacity = ArraysSupport.newLength(oldCapacity, minCapacity - oldCapacity, /* minimum growth */ oldCapacity >> 1 /* preferred growth */); return elementData = Arrays.copyOf(elementData, newCapacity); } else { return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; } }
计算 newCapacity 的代码
/** * Computes a new array length given an array's current length, a minimum growth * amount, and a preferred growth amount. The computation is done in an overflow-safe * fashion. * * This method is used by objects that contain an array that might need to be grown * in order to fulfill some immediate need (the minimum growth amount) but would also * like to request more space (the preferred growth amount) in order to accommodate * potential future needs. The returned length is usually clamped at the soft maximum * length in order to avoid hitting the JVM implementation limit. However, the soft * maximum will be exceeded if the minimum growth amount requires it. * * If the preferred growth amount is less than the minimum growth amount, the * minimum growth amount is used as the preferred growth amount. * * The preferred length is determined by adding the preferred growth amount to the * current length. If the preferred length does not exceed the soft maximum length * (SOFT_MAX_ARRAY_LENGTH) then the preferred length is returned. * * If the preferred length exceeds the soft maximum, we use the minimum growth * amount. The minimum required length is determined by adding the minimum growth * amount to the current length. If the minimum required length exceeds Integer.MAX_VALUE, * then this method throws OutOfMemoryError. Otherwise, this method returns the greater of * the soft maximum or the minimum required length. * * Note that this method does not do any array allocation itself; it only does array * length growth computations. However, it will throw OutOfMemoryError as noted above. * * Note also that this method cannot detect the JVM's implementation limit, and it * may compute and return a length value up to and including Integer.MAX_VALUE that * might exceed the JVM's implementation limit. In that case, the caller will likely * attempt an array allocation with that length and encounter an OutOfMemoryError. * Of course, regardless of the length value returned from this method, the caller * may encounter OutOfMemoryError if there is insufficient heap to fulfill the request. * * @param oldLength current length of the array (must be nonnegative) * @param minGrowth minimum required growth amount (must be positive) * @param prefGrowth preferred growth amount * @return the new array length * @throws OutOfMemoryError if the new length would exceed Integer.MAX_VALUE */ public static int newLength(int oldLength, int minGrowth, int prefGrowth) { // preconditions not checked because of inlining // assert oldLength >= 0 // assert minGrowth > 0 int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) { return prefLength; } else { // put code cold in a separate method return hugeLength(oldLength, minGrowth); } } private static int hugeLength(int oldLength, int minGrowth) { int minLength = oldLength + minGrowth; if (minLength < 0) { // overflow throw new OutOfMemoryError( "Required array length " + oldLength + " + " + minGrowth + " is too large"); } else if (minLength <= SOFT_MAX_ARRAY_LENGTH) { return SOFT_MAX_ARRAY_LENGTH; } else { return minLength; } }

remove(Object o)

/** * Removes the first occurrence of the specified element from this list, * if it is present. If the list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index * {@code i} such that * {@code Objects.equals(o, get(i))} * (if such an element exists). Returns {@code true} if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present * @return {@code true} if this list contained the specified element */ public boolean remove(Object o) { final Object[] es = elementData; final int size = this.size; int i = 0; //判断删除的元素是否存在 found: { if (o == null) { for (; i < size; i++) if (es[i] == null) break found; } else { for (; i < size; i++) if (o.equals(es[i])) break found; } return false; } fastRemove(es, i); return true; } /** * Private remove method that skips bounds checking and does not * return the value removed. */ private void fastRemove(Object[] es, int i) { modCount++; final int newSize; if ((newSize = size - 1) > i) System.arraycopy(es, i + 1, es, i, newSize - i); es[size = newSize] = null; }
调用JNI方法复制数组,将被删除元素之后的所有元素从i复制到原来数组,相当于i之后的元素往前移动一位
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);