ArrayList jdk1.8基础和源码分析

241 阅读3分钟

ArrayList是基于数组实现的列表,数组的物理存储空间连续,修改和查看的复杂度为O(1),添加和删除需要更多操作。

构造函数ArrayList()

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
 
    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;

//指定初始容量,如果initialCapacity>0,会分配一段内存空间
    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);
        }
    }

//默认是个空数组
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

//指定elementData和elementData的size
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

add(E element) 添加

进行是否需要扩容的判断

  • add(E e) 在数组的末端添加对象

  • add(int index, E element) 在指定的索引位置上添加对象,需要对index后的所有对象往后移动一位

//在数组的末端添加对象
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e; 
        return true;
    }

//在指定的索引位置上添加对象
    public void add(int index, E element) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
    }
    
    //
     private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); //取DEFAULT_CAPACITY和minCapacity中的最大值
        }
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity); //如果minCapacity > elementData.length,则扩容
    }

remove(index) 删除

索引判断,是否数组越界

取出elementData[index], 并最终返回oldValue

如果不是移除最后一个对象,需要对index+1之前的所有对象往前移一位

移除后,elementData[--size]=null 清除引用

 public E remove(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            
        modCount++;
        E oldValue = (E) 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;
    }

set(index, element) 改

索引判断,是否数组越界

给elementData[index]重新赋值,并返回oldValue

public E set(int index, E element) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        E oldValue = (E) elementData[index];
        elementData[index] = element;
        return oldValue;
    }

get(index) 查

索引判断,是否数组越界

取出elementData[index]并返回

  public E get(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        return (E) elementData[index];
    }

grow() 扩容

minCapacity取的是DEFAULT_CAPACITY (10)和minCapacity (size + 1)中的最大值

newCapacity = 1.5倍oldCapacity, oldCapacity是elementData.length,扩容原来的1/2倍

如果newCapacity > MAX_ARRAY_SIZE,如果minCapacity > MAX_ARRAY_SIZE, newCapactiy取Integer.MAX_VALUE,否则取MAX_ARRAY_SIZE


 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 
 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        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;
    }

size()

返回的是列表包含的对象个数,而不是elementData.length, size肯定是小于等于elementData.length,size+1如果大于elementData.length,就需要扩容啦!

 public int size() {
        return size;
    }

isEmpty()

同上,如果size==0,则列表里没有任何对象。add()会进行size++,remove()会进行size--。

 public boolean isEmpty() {
        return size == 0;
    }

contains()

get(index)可以通过索引得到相应的value,indexOf(Object)可以根据value返回索引。

indexOf(Object)返回的索引>0,则列表里存在value,否则不存在

    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    public int indexOf(Object o) {
        if (o == null) { //遍历匹配
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else { //遍历匹配
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

总结

  • ArrayList是基于数组实现的列表,数组的物理存储空间连续,修改和查看的复杂度为O(1),添加和删除需要更多操作。

  • 根据下标索引进行定位,所以set和get方便;add和remove需要进行批量移动。