ArrayList原理和源码分析

集合ArrayList的原理和源码

ArayList是java的一个集合类,实现了List接口。应用非常广泛,数据库查询结果集、excel导入解析、json数据解析,网站数据爬虫解析等等都会使用到。

1.创建

//创建一个空的数组
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//创建一个指定长度的数组
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);
    }
}

2.主要的属性

 /**
     * Default initial capacity.
      默认初始化容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
      用于共享一个空的数据实例
     */
    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.
     */
    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.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     * 集合的长度
     * @serial
     */
    private int size;

3.add()

//append 一个元素到list的末尾
public boolean add(E e) {
    //第一次add时会初始化Object[]
     ensureCapacityInternal(size + 1);  // Increments modCount!!
     elementData[size++] = e;
     return true;
 }

核心方法ensureCapacityInternal(size + 1);

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//方法是返回数组的下标
//1.如果第一次创建,则会返回DEFAULT_CAPACITY
//2.如果不是第一次创建,则返回当前的下标
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
//
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    //根据当前的数组的长度得到当前数据要放入到那个下标中,如果超过了数组的长度,则对数组进行一个扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

grow(minCapacity)

//扩容的计算
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //扩容1.5倍,oldCapacity >> 1是取原来数组长度的一般,在加上原来的长度,即1.5倍,
    //注意5>>1的值为2
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //此处判断当要扩容的长度大于MAX_ARRAY_SIZE时的一些判断,具体看代码
    //
    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 final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//超过MAX_ARRAY_SIZE,就返回Integer的最大值,否则就是minCapacity
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

4.其他的一些方法

4.1contains(e)

//真正调用的是indexOf(o)
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}
//其实都是用的for循环去判断数组中有没有包含这个元素,分为了2中情况,o=null和o!=null
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.2 set(int index, E element)

//其实就是对已有元素的一个更新赋值,并返回原来的值
public E set(int index, E element) {
    //检查当前出入的index是否符合规范,如果查过当前数组长度,则会抛出IndexOutOfBoundsException
    rangeCheck(index);
    //拿到index下标的元素,然后进行更新赋值,同时返回原来的值
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

4.3 get(int index)

//检查index,然后返回元素,这就是数组的查询效率
public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

4.4remove(int index)

//删除对应下标的元素并返回 
public E remove(int index) {
     rangeCheck(index);

     modCount++;
     E oldValue = elementData(index);
	//计算要copy的数据的长度
     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;
 }

4.5 remove(Object o)

//根据o先查找到数据所在的下标,然后再调用fastRemove方法,删除的逻辑和上文的一致
//次方法返回的是boolean类型
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;
}

4.6size()

//在每次add或者remove的时候会对size的值有一个维护,
public int size() {
    return size;
}

4.7isEmpty()

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

4.8clear()

//将数组的每一个元素置位null,并将size设置为0
public void clear() {
     modCount++;

     // clear to let GC do its work
     for (int i = 0; i < size; i++)
         elementData[i] = null;

     size = 0;
 }

4.9addAll()

求2个集合的并集

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    //这里是对数组的一个扩容
    ensureCapacityInternal(size + numNew);  // Increments modCount
    //2个list的数据合并,通过数组的一个copy
    System.arraycopy(a, 0, elementData, size, numNew);
    //合并完成后list 的集合长度等于2个list的和
    size += numNew;
    return numNew != 0;
}

4.10retainAll()

求2个集合的交集

public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    //真正执行的方法,注意这里的一个参数,当参数为true时是获取交集,当参数为false时,是获取差集
    return batchRemove(c, true);
}

private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            //核心代码,就是这里去判断是否了目标预算, 如果包含则是属于交集,如果不包含则是差集。
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws. 
        //此处是在c.congtains()发生了异常,则这时的r!=size,就需要将r以后的数据直接拷贝到			//elementData中,并计算w的值
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        //如果w!=size,说明2个集合中存在不同的元素,则需要将w下标之后的数据置位null
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}

4.11removeAll()

求2个集合的差集

//具体参见上面的batchRemove方法
public boolean removeAll(Collection<?> c) {
     Objects.requireNonNull(c);
     return batchRemove(c, false);
 }

4.12无重复并集

list2.removeAll(list1);
list1.addAll(list2);
posted @ 2019-08-06 10:39  wxzj  阅读(88)  评论(0编辑  收藏  举报