Java的arraylist源码分析

最近在看hotspot源码时顺手把JDK的一部分常用的类代码也看了一下,并在源码做了记录,这里分享出来。

代码上都有我的注释,和自己的理解,只贴了一部分我觉得比较常见的代码。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     * 默认的数组容量为10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     * 用于空实例的共享空数组实例。
     * 这里看到这个数组是static的也就是全部的arraylist实例都公用这一个数组
     * 初始化capacity=0时使用这个
     * 那么这个数组根据他的注释理解就是,当我们的一个arraylist被new出来但是内部还没有元素时候他的引用就是指向这个全局公用的数组的
     *
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     * 共享的空数组实例,用于默认大小的空实例。
     * 我们将其与EMPTY_ELEMENTDATA区别开来,
     * 以了解添加第一个元素时需要充气多少。
     *
     * 这里就是当我们new一个arraylist但是没有压入元素也没有初始化capacity就会默认使用这个数组
     * 这个数组主要的功能我觉得可能是为了减少内存的消耗,如果我们new了一个arraylist但是一直没有使用那么就可以避免他在堆中
     * 开辟一个新的array了,而是全部满足这个条件的list都使用这个全局数组,这样来减少内存占用(个人理解),
     *
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 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.
     * 这里是ArrayList元素存储到的数组缓冲区。
     * ArrayList的容量是此数组缓冲区的长度。添加第一个元素时,任何具有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * 的空ArrayList都将扩展为DEFAULT_CAPACITY。
     *
     * 这里正好印证了对上面那个方法的理解,在我们第一次压入元素时,开始开辟数组内存,
     * 这里会根据我们之前的引用如果是DEFAULTCAPACITY_EMPTY_ELEMENTDATA 那么就代表我们new的时候并没有安装capacity,
     * 这就会按照默认大小10来开辟。
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * 代表了当前arraylist的大小。并不是数组大小而是他所包含的元素数量
     * @serial
     */
    private int size;

    /**
     * Constructs an empty list with the specified initial capacity.
     * 构造一个具有指定初始容量的空列表。
     *
     * @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) {//如果初始化容量为0,则使用第一个array
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     * 构造一个初始容量为10的空列表。这里会直接使用全局数组
     */
    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.
     *
     * 构造一个包含指定集合的元素的列表,其顺序由集合的迭代器返回。
     * @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) {
        elementData = c.toArray();//首先通过集合接口规定的toArray方法将目标集合转换为数组,并直接传递引用给我们当前所维护的elementdata
        if ((size = elementData.length) != 0) {//判断数组的长度不等于0
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            //c.toArray可能(不正确)不返回Object [](请参阅6260652)
            if (elementData.getClass() != Object[].class)//这里就是toarray方法出问题时
                //通过array的copy方法来得到数组
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {//这种情况是我们目标集合的数组是空的
            // replace with empty array.
            // 直接引用EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     * 将该<tt> ArrayList </ tt>实例的容量调整为
     * 列表的当前大小。
     * 应用程序可以使用此操作来最大程度地减少<tt> ArrayList </ tt>实例的存储
     *
     * 根据方法名就可以看出来,这个方法目的就是将内部维护的数组进行切割来使的,elementdata.length==size
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

    /**
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     * 如有必要,增加此<tt> ArrayList </ tt>实例的容量,
     * 以确保它至少可以容纳最小容量参数指定的元素数量。
     *
     *
     * 这里可能就是我们要找的扩容方法了。先不下结论继续往下看看
     * @param   minCapacity   the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;
        //上面这个逻辑是计算压入当前元素所需要的最小空间是多少,

        if (minCapacity > minExpand) {//这里对我们需要的空间进行比较,看看是否需要扩容
            ensureExplicitCapacity(minCapacity);//ensureExplicitCapacity方法是一个扩容的私有方法
        }
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    //确认是否需要扩容,在这个方法里调用grow方法进行扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//这个判断说明最小的需求容量都比现在所有的容量要大,需要扩容
            grow(minCapacity);//这样看来扩容的来源应该是grow方法
    }

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     *
     * 要分配的最大数组大小。
     * 一些VM在数组中保留一些标题字。
     * 尝试分配更大的阵列可能会导致
     * OutOfMemoryError:请求的阵列大小超出VM限制
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 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);//通过移位方法使newcavity=oldcavity+(oldcavity/2)
        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);//通过arrays。copy方法对数组进行扩充
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow,数组所需最小容量超过限制
            throw new OutOfMemoryError();//抛出内存溢出异常
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    /**
     * Returns the number of elements in this list.
     *
     * @return the number of elements in this list
     */
    public int size() {
        return size;
    }

    /**
     * Returns <tt>true</tt> if this list contains no elements.
     *
     * @return <tt>true</tt> if this list contains no elements
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Returns <tt>true</tt> if this list contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this list contains
     * at least one element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this list is to be tested
     * @return <tt>true</tt> if this list contains the specified element
     *
     *
     * 这里判断数组中是否存在目标对象,通过indexOF方法,对返回的索引进行判断如果大于0
     * 则意味着数组中存在有这样一个元素的位置,否则就是没有这个元素
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }//直接根据数组的索引是否存在来判断

    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     *
     * 返回数组中第一个出现的目标元素所储存的索引位置
     */
    //从前往后遍历实现
    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;
    }

    /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     *
     * 返回数组中第最后一个出现的目标元素所储存的索引位置
     */
    //从后往前遍历实现
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     *
     * 一个来自于object所规定的拷贝算法,
     * 要求array.clone().elementdata != array.element && array.clone().elementdata.equals(array.element) == true
     */
    //把数组复制一个直接传过去
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            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);
        }
    }

    /**
     * Returns an array containing all of the elements in this list
     * in proper sequence (from first to last element).
     *
     * <p>The returned array will be "safe" in that no references to it are
     * maintained by this list.  (In other words, this method must allocate
     * a new array).  The caller is thus free to modify the returned array.
     *
     * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * @return an array containing all of the elements in this list in
     *         proper sequence
     *
     *
     *  这里要注意一下了,这个TOARRAY方法返回的数组并不是array内部维护的数组而是在内存中新建立的一个拷贝数组
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    /**
     * Returns an array containing all of the elements in this list in proper
     * sequence (from first to last element); the runtime type of the returned
     * array is that of the specified array.  If the list fits in the
     * specified array, it is returned therein.  Otherwise, a new array is
     * allocated with the runtime type of the specified array and the size of
     * this list.
     *
     * <p>If the list fits in the specified array with room to spare
     * (i.e., the array has more elements than the list), the element in
     * the array immediately following the end of the collection is set to
     * <tt>null</tt>.  (This is useful in determining the length of the
     * list <i>only</i> if the caller knows that the list does not contain
     * any null elements.)
     *
     * @param a the array into which the elements of the list are to
     *          be stored, if it is big enough; otherwise, a new array of the
     *          same runtime type is allocated for this purpose.
     * @return an array containing the elements of the list
     * @throws ArrayStoreException if the runtime type of the specified array
     *         is not a supertype of the runtime type of every element in
     *         this list
     * @throws NullPointerException if the specified array is null
     *
     * 这个跟上面那个是差不多的功能,不过是可以规定数组的范型了并将所维护的数组内容拷贝到目标数组
     */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)//首先判断传进来目标数组够不够容纳我们所谓户的数组
            // Make a new array of a's runtime type, but my contents:
            //创建一个新的数组而不是使用传进来的目标数组,因为目标数组大小不够
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    // Positional Access Operations

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[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}
     *
     * 这个就是get方法了
     */
    public E get(int index) {
        rangeCheck(index);//先判断目标索引是否合法
        //返回目标索引下的数组元素
        return elementData(index);
    }

    /**
     * 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) {
        rangeCheck(index);//判断目标索引是否合法

        //将要被替代掉的老元素拿过来,通过给予一个新的根可达引用来做的
        E oldValue = elementData(index);
        //将新的元素放入数组指定的索引位置
        elementData[index] = element;
        //返回刚刚老元素索引
        return oldValue;
    }

    /**
     * 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})
     *
     * 也是十分常用的add方法
     */
    public boolean add(E e) {
        //先确认是否需要扩容再加入
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //加入新元素,这里是size++,逻辑没有问题,因为size代表元素的个数,不包括0 所以size=elementdata.length+1
        //这里直接在index==size位置插入元素,之后在做size++
        elementData[size++] = e;
        return true;
    }

    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     * 将指定的元素插入此列表中的指定位置。
     * 将当前在该位置的元素(如果有的话)
     * 和任何后续元素向右移动(向其索引添加一个)。
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);//索引是否合法

        //判断是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //通过复制数组的方式来完成数组内元素的移动,将index位置空出来
        //这里源数组和目标数组都是一个,也就不需要在改变引用了,
        //有时间可以去看看system的arraycopy方法,蛮好用的一个静态方法
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //插入新元素
        elementData[index] = element;
        size++;
    }

    /**
     * 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}
     * 
     * 这个和前面的set逻辑基本一样
     */
    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);
        //这里很细节的移除根可达,来GC被移除的元素
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

    /**
     * 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
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> 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 <tt>true</tt> if this list contained the specified element
     * 
     * 这里逻辑简单就是一个全局遍历,按照要去移除元素,不过看到了一个叫做fastremove的方法,这个要去看一下
     */
    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;
    }

    /*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     * 专用的remove方法,跳过边界检查,并且不返回删除的值。
     */
    private void fastRemove(int index) {
        modCount++;
        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
    }

    /**
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     * 
     * 这里是清除数组,没有直接改变引用而是通过去除元素的可达性来是他们被GC来实现的
     * 
     */
    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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值