ArrayList底层实现

ArrayList 底层是有数组实现,实际上存放的是对象的引用,而不是对象本身。当使用不带参的构造方法生成ArrayList对象时,实际会在底层生成一个长度为10的数组

当添加元素超过10的时候,会进行扩容 基本上是原来的1.5倍  oldlenth+(oldlenth>>1) 1.5oldlength

>> 表示右移  10>>1(000 1010)右移一位为 5(000 0101)

我们来看下源码

ArrayList a = new ArrayList(); 新建一个arraylist 点进去会出现

 /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

  头说明非常清楚,创建一个空的list,初始化他的长度

  /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] 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 == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;

  DeFAULT_CAPACITY:是某认的长度10

  EMPTY_ELEMENTDATA:是list底层实现的数组

  transient Object[] elementData:存储数组元素的缓冲区,arraylist的容量是这个数组的长度,任何arraylist与elementData=EMPTY_ELEMENTDATA将会被扩展到添加第一个元素时的DEFAULT_CAPACITY

  

  transient关键字 修饰 表示在序列化的时候,被修饰的不会被序列化。

但是在arraylist中不是这样的,arraylist实现了序列化的writeObject()可指定序列化,arrayList将强制把elementData序列化,但是arryaList内部序列化的时候,因为初始

容量有10 ,但是我可能只有5个元素,那么剩下的就会是空值,在序列化的时候会把空值序列化进去,那么就没有意义,如果直接标记序列化则会把空值序列化进去,用transient修饰后然后重写writeObject()方法将其序列化,只序列化存储元素而不是整个数组,这样可以降低序列化的传输量,从而来提示速度

 /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
     * is, serialize it).
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

  这里会去根据size的长度去遍历,然后将对应值取出来序列化

boolean add方法 是将改对象加入到数据的最末端

void add(int index,E element)方法则是要从指定位置+1开始往后使用arraycopy方法赋值数组操作,之后在对对应元素赋值

void add方法

 /**
     * 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!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

boolean add方法

  /**
     * 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})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

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

        ensureExplicitCapacity(minCapacity);
    }


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

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

 /**
     * 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;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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);
    }

我们来一句一句的分析

进入add方法首先就是ensureCapacityInternal(size+1)设置内部缓冲区,在当前基础上+1,然后将元素添加到数组中

ensureCapacity()方法

  首先会判断数组对象是不是初始化数组,如果是的话,则会用初始化值也就是默认的长度10和我们现在传给他的长度做对比

如果传给他的值大于10则minCapacity最小容量为传的值,反之则为10.然后去设置缓冲区大小进入 ensureExplicitCapacity(minCapacity);

 ensureExplicitCapacity(minCapacity)

  首先 modCount会自增,然后判断传过来的最知晓容量是否大于现有数组的长度,如果大于则扩容进入grow(minCapacity)方法

gorw(minCapacity)

   方法中,会想当前数组的长度基础上右移一位然后加上当前数组的长度相当于1.5倍,然后用新得到的长度和最小容量去对比

如果小于最小容量,则新容量为最小容量,反正则不变。然后新容量会和list最大长度对比,如果他比list最大值还大则返回默认定义的MAX_VALUE

最后调用copy方法进行赋值

本文初次读源码。。里面可能会有很多错误或者意思描述不清的地方,希望大家指出来,我好改正以免误导别人。。。大家一起共同学习进步

原文地址:https://www.cnblogs.com/zmblog/p/8676595.html