Java ArrayList源码浅析

ArrayList

特点

数组实现,能够随机访问,增加和删除慢

实现

    //默认初始容量:10
    private static final int DEFAULT_CAPACITY = 10;

    private static final Object[] EMPTY_ELEMENTDATA = {};

    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.
     */
	 	 //elementData.length是实际的空间
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
	   //size是ArrayList的容量
    private int size;

声明

默认构造函数

指定缓冲区为DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

    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);
        }
    }

带集合参数构造函数

将集合对象转换为数组,更新ArrayList的size属性为集合对象的大小。
如果集合不为空:

  • 判断传入的集合是否为ArrayList,如果是的话直接更改elementData的引用;
  • 如果集合类不是ArrayList,通过Arrays.copyOf()进行扩容和复制。

如果集合为空,则将elementData初始化为EMPTY_ELEMENTDATA

    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

压缩容量

当数组扩容后,就算删除了元素,elementData仍然是扩容之后的大小,只是size会改变。
为了减少ArrayList占用的空间,可以通过trimToSize将elementData的空间压缩到size的大小。

    public void trimToSize() {
        modCount++;  //记录被修改的次数,带modCount的都是线程不安全?
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

是否包含某元素

    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 {@code i} such that
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        return indexOfRange(o, 0, size);
    }

    int indexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = start; i < end; i++) {
                if (es[i] == null) { //如果找null,用==判等
                    return i;
                }
            }
        } else {
            for (int i = start; i < end; i++) {
                if (o.equals(es[i])) { //非空值则使用equals
                    return i;
                }
            }
        }
        return -1;
    }

上述函数是寻找o第一次出现的索引,设计者提供了lastIndexOf()函数用于寻找最后出现的索引,本质上就是从elementData的末尾开始查找

获取元素

    E elementData(int index) {
        return (E) elementData[index];
    }

    @SuppressWarnings("unchecked")
    static <E> E elementAt(Object[] es, int index) {
        return (E) es[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}
     */
    public E get(int index) {
			/*
			if (index < 0 || index >= length)
					throw outOfBoundsCheckIndex(oobef, index, length);
			*/
        Objects.checkIndex(index, size);
        return elementData(index);
    }

删除元素

删除指定索引位置的元素

    public E remove(int index) {
        Objects.checkIndex(index, size);
        final Object[] es = elementData;

        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        fastRemove(es, index);

        return oldValue;
    }
	
    private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
		//将i之后的newSize-i个元素复制到前面
        if ((newSize = size - 1) > i)
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }

删除指定值的元素

    public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
		//寻找元素下标,调用私有的remove方法完成删除
        found: {
            if (o == null) {
                for (; i < size; i++)
                    if (es[i] == null)
                        break found;
            } else {
                for (; i < size; i++)
                    if (o.equals(es[i]))
                        break found;
            }
            return false;
        }
        fastRemove(es, i);
        return true;
    }

插入元素

    public void add(int index, E element) {
	   //检查index是不是小于0或者大于size
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
		//如果size的大小和elementData的长度一致,说明缓冲区已满
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow(); //扩容
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element; //更新缓冲区
        size = s + 1;  //更新size
    }
	
    private Object[] grow() {
        return grow(size + 1); 
    }

扩容函数grow(minCapacity),并非直接扩容到minCapacity,而是通过ArraySupport.newLength()计算一个新的容量。

    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

新的容量preLength=oldCapacity + Math.max(minCapacity - oldCapacity, oldCapacity/2),也就是最少增长oldCapacity/2 。

  • 如果新的容量preLength < SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8,则是合法的容量。

  • 如果新的容量 > SOFT_MAX_ARRAY_LENGTH,则需要调用hugeLength进行特殊处理:

    • 如果oldCapacity + minGrowth < 0,说明溢出了,抛出异常;
    • 如果oldCapacity + minGrowth < SOFT_MAX_ARRAY_LENGTH,返回 SOFT_MAX_ARRAY_LENGTH;
    • 如果oldCapacity + minGrowth > SOFT_MAX_ARRAY_LENGTH,返回oldCapacity + minGrowth。
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // preconditions not checked because of inlining
        // assert oldLength >= 0
        // assert minGrowth > 0

        int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
        if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
            return prefLength;
        } else {
            // put code cold in a separate method
            return hugeLength(oldLength, minGrowth);
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值