源码学习之ArrayList

来源:互联网 发布:为什么黑人很懒 知乎 编辑:程序博客网 时间:2024/05/08 16:29

ArrayList源码分析学习

  1. 首先是ArrayList的定义

    //继承AbstractList抽线类,实现了List、RandomAccess、Cloneable和Serializable接口public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  2. ArrayList源码开头定义的几个成员变量

        //表示ArrayList的默认容量为10,但是在我们初始化为一个空的ArrayList的时候容量并不是10,具体下文解释    private static final int DEFAULT_CAPACITY = 10;    //表示空的一个元素数组,在初始化一个空的ArrayList的时候,elementData就等于这个EMPTY_ELEMENTDATA    private static final Object[] EMPTY_ELEMENTDATA = {};    //这个就是实际存储数据的数组,从这个可以看出ArrayList是数组实现的    transient Object[] elementData;     //这个就是数组列表的存储数据的size了    private int size;
  3. 构造函数,ArrayList一共提供了三个构造函数。

    //第一个构造函数,参数initialCapacity为初始化容量,如果initialCapacity为负,则抛出IllegalArgumentException异常,否则就初始化elementData为一个大小为initialCapacity的数组public ArrayList(int initialCapacity) {        super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);        this.elementData = new Object[initialCapacity];    }//第二个构造函数,不传入参数,这个时候elementData,就设置成上文定义的空数组,EMPTY_ELEMENTDATA,这个时候数组链表的容量是0,并不是10.public ArrayList() {        super();        this.elementData = EMPTY_ELEMENTDATA;    }//第三个构造函数,传入参数为另一个集合。这个时候就是用传入集合的元素初始化数组链表。public ArrayList(Collection<? extends E> c) {        elementData = c.toArray();        size = elementData.length;        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elementData.getClass() != Object[].class)            elementData = Arrays.copyOf(elementData, size, Object[].class);    }
  4. ArryList扩容机制

     //保证容量,这块是外部手动调用扩容的。minCapacity是需要的最小容量。    public void ensureCapacity(int minCapacity) {        //最小扩展,如果elementData等于EMPTY_ELEMENTDATA,那么minExpand设置为DEFAULT_CAPACITY,否则minExpand等于0        int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;        //如果最小需要容量大于最小扩展,那么这个时候需要保证最小需要容量的数值        if (minCapacity > minExpand) {            ensureExplicitCapacity(minCapacity);        }    }
      //保证容量,这是内部函数调用用来扩容的,在每次添加元素的时候都会调用    private void ensureCapacityInternal(int minCapacity) {    //elementData == EMPTY_ELEMENTDATA时,这个时候minCapacity去DEFAULT_CAPACITY和minCapacity大的一个。    //在初始化一个空的ArrayList时,elementData == EMPTY_ELEMENTDATA,这个时候添加一个元素,检查容量,minCapacity传递的是size+1,也就是1,这个时候minCapacity等于DEFAULT_CAPACITY。        if (elementData == EMPTY_ELEMENTDATA) {            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }
    //上面两个函数调用的函数 private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // overflow-conscious code        //如果需要保证的最小容量大于elementData的长度,那么这个时候需要扩容        if (minCapacity - elementData.length > 0)            grow(minCapacity);    }
     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //具体的扩容函数    private void grow(int minCapacity) {        int oldCapacity = elementData.length;        //新容量,是原来的容量的1.5倍        int newCapacity = oldCapacity + (oldCapacity >> 1);        //如果新容量不能满足最小容量要求,那么新容量设置成minCapacity        //从空添加一个元素的时候,minCapacity==DEFAULT_CAPACITY,这个时候容量就扩充到DEFAULT_CAPACITY了。        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        //如果新容量大于MAX_ARRAY_SIZE,那么新容量设置成Integer.MAX_VALUE        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);    }
    //如果minCapacity大于MAX_ARRAY_SIZE,那么返回 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+add_size,elementData是空数组的时候,容量会变成DEFAULT_CAPACITY,也就是10。elementData不是空数组的时候,如果size+add_size大于容量,也即是elementData.length,那么就扩容,扩容的方法是首先扩容1.5倍的原容量,然后判断1.5的原容量是否大于size+add_size,如果不大于,那么新容量设置成size+add_size,再检查size+add_size是否大于最大容量Integer.MAX_VALUE - 8,如果大于那么就设置成Integer.MAX_VALUE

  5. ArrayList常用操作

    1. size()

      public int size() {            return size;        }
    2. isEmpty()

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

      public boolean contains(Object o) {        return indexOf(o) >= 0;    }//找到elementData中第一次出现o的下标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;}
    4. get()

      public E get(int index) {        //是否越界判断        rangeCheck(index);        return elementData(index);    }private void rangeCheck(int index) {if (index >= size)    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}
    5. set()

      //修改下标index处的元素public E set(int index, E element) {        rangeCheck(index);        E oldValue = elementData(index);        elementData[index] = element;        return oldValue;    }
    6. add()

      //在后面添加一个元素 public boolean add(E e) {         //判断容量        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    } //在下标index处添加一个元素,有数据的移动public void add(int index, E element) {    rangeCheckForAdd(index);    ensureCapacityInternal(size + 1);  // Increments modCount!!    System.arraycopy(elementData, index, elementData, index + 1,                     size - index);    elementData[index] = element;    size++;}
    7. remove()

      //删除下标为index的元素,需要后面的元素进行移动public E remove(int index) {        rangeCheck(index);        modCount++;        E oldValue = 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;    }//删除赌徒个等于o的元素public boolean remove(Object o) {if (o == null) {    for (int index = 0; index < size; index++)        if (elementData[index] == null) {            fastRemove(index);            return true;        }} else {    for (int index = 0; index < size; index++)        if (o.equals(elementData[index])) {            fastRemove(index);            return true;        }}return false;}
    8. clear

      public void clear() {        modCount++;        // clear to let GC do its work        for (int i = 0; i < size; i++)            elementData[i] = null;        size = 0;    }
0 0
原创粉丝点击