jdk源码阅读之——arraylist

首先看一下他的构造函数:

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

其实arraylist还有其他的构造函数,可以指定数组的长度,这里先从最基本的入手

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

这个DEFAULTCAPACITY_EMPTY_ELEMENTDATA 其实就是一个空的数组,在这里的作用就是为了表示这是一个空的的数组
而elementData 是arraylist真正用来存放数据的地方
那么可以注意到,初始话完成以后,整个数组的长度就是0,arraylist 正在开始让他有长度,是在add操作的时候完成的,下面去看下add操作

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

总共两端代码 后一段好理解,就是给数组赋值,然后把代表数组长度的size+1

我们进入ensureCapacityInternal 去看看。注意他的参数,是当前数组的长度+1

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

        ensureExplicitCapacity(minCapacity);
    }

从参数名minCapacity 的字面意思我们就能知道,意思是最小的容量,
之后先判断数组是不是一个空数组 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 如果是,我们看下当前需要的最小容量和DEFAULT_CAPACITY 谁更加大,这个DEFAULT_CAPACITY 是arraylist 的一个常量是10,所以看到这里我们已经知道arraylist默认的长度是10。
好了这里取最大的值,所以我们的`minCapacity 变成了10

我们继续看下一个函数ensureExplicitCapacity 先看字面意思是明确的确保容量,看来arraylist很谨慎

 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

首先会注意到这里有一个modCount,他其实和现在我们分析的没关系,这是一个用来记录操作次数的东西,你增加删除读取都会记录,主要用在线程安全上

然后是minCapacity - elementData.length > 0 其实就是比较大小,如果当前需要的空间minCapacity 大于elementData 能提供的空间,我们就需要扩容,也就是grow操作
否则就完事了,我们知道现在elementData的长度为0,那肯定要扩容了,进入grow看看

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//拿出现在数组的长度
        //扩容,扩容方式就是原来的长度+原来长度的一半,也就是右移一位
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //就我们分析的情况 扩容后的长度是0+0/2还是0
        //这里就看下扩容后的长度能不能满足最小需要的长度,现在看来是不能的那就用最小需要的长度代替扩容的长度吧
        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:
        //扩容,现在我们的数组长度为10啦
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

初始化分析到这里就结束了,后面看几个常用的操作
get set remove 其实真的大同小异

先看get

 public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

这里涉及到第一个函数rangeCheck

 private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

他做了一个判断,当前请求的位置是不是在数组的长度范围内,不是抛出异常,是的话啥事没有

然后是elementData

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

这个就没什么好讲了就是把数组指定位置取出来返回,但请牢记这个函数,后面都会用到他

现在看remove

 public E remove(int index) {
         //越界检查
        rangeCheck(index);
        //操作记录
        modCount++;
        //拿到这个要删除的点
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        //这里的操作就是把要删除位置后面的数据都向前一定一位
        //System.arraycopy(要操作的数组,开始操作的位置,目标数组,目标数组开始的位置,复制的长度)
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

最后看set

   public E set(int index, E element) {
       //越界检查
        rangeCheck(index);
        //拿到旧值
        E oldValue = elementData(index);
        //赋新的值
        elementData[index] = element;
        //返回旧值
        return oldValue;
    }

最后我们看一下迭代器部分的代码

 private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        //我们看到arraylist开始使用哪个奇怪的一直在计数的变量的,先把他复制一份
        int expectedModCount = modCount; 
        //判断还有没有下一个
        public boolean hasNext() {
            //看当前阅读的指针有没有超出总长度
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        //这是访问下一个
        public E next() {
            //检查
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
             //到下一个节点
            cursor = i + 1;
            //返回当前遍历节点的数据
            return (E) elementData[lastRet = i];
        }
        //删除节点
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }


        final void checkForComodification() {
        //如果两个值不相等,说明在我们便利的时候有线程动了这个arraylist ,这里抛出异常快速失败!
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

总结一下arraylist 底层是数组,默认长度是10,可以自主扩展,扩展的长度是
原数组的长度+原数组长度/2 也就是新的数组是原来的1.5倍

猜你喜欢

转载自blog.csdn.net/zjsxxzh/article/details/79302546