ArrayList add get remove 源码解析
ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
add方法:
/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { //处理动态数组的容量,不够则扩充 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //容器第一次添加数据,设置容器容量大小初始值 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //根据给定容器大小的下限值,判断是否扩充容器 ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { //fail-fast机制的基准值 modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) //容器大小不足,扩充 grow(minCapacity); } /** * 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 */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //每次扩充为原容器大小的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //兜底机制,扩充后的容器大小如果还不满足条件,则使用给定的容器大小 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果扩充后的容器大小值超出容器规定的上限,两种情况 //1 是大小超出了int的最大值,成为负数,直接抛出异常 //2 是大小超出了容器上限值,但是还没超出int的最大值,则容器大小初始化为int的最大值 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
简而言之,就是一个可以动态扩容的数组,
看get方法
/** * 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) { rangeCheck(index); return elementData(index); } /** * Checks if the given index is in range. If not, throws an appropriate * runtime exception. This method does *not* check if the index is * negative: It is always used immediately prior to an array access, * which throws an ArrayIndexOutOfBoundsException if index is negative. */ private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } // Positional Access Operations @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; }
首先检查索引是否越界,越界则抛出异常,否则返回数据。
remove方法:
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { //检查索引是否越界 rangeCheck(index); modCount++; //保留原有值,作为返回数据 E oldValue = elementData(index); //计算需要移动的数组的数据长度 int numMoved = size - index - 1; if (numMoved > 0) //把index后面的所有数据往前移动一位 System.arraycopy(elementData, index+1, elementData, index, numMoved); //删除数组最后一个多余的数据,便于gc回收 elementData[--size] = null; // clear to let GC do its work return oldValue; }
比较了下add和remove两者,发现add虽然有扩容机制,但是remove并没有缩容机制。随着元素的删除,只是把对应元素的引用释放,并没有把数组本身的容量大小进行调整。