[Source] Java collection classes -ArrayList

First, the class inheritance relationship

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList AbstractList succession, and the RandomAccess List also achieved (an empty interface, the interface is marked.), The Cloneable (may be cloned), the Serializable interface.

Second, the class attribute

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

    //空对象数组(initialCapacity == 0时返回)
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //调用无参构造方法,返回的是该数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //元素数组,保存添加到ArrayList中的元素
    transient Object[] elementData;
    
    //ArrayList大小
    private int size;

elementData transient is modified, it can not be serialized elementData. But ArrayList is can be serialized, this is why?

  • Because there are two methods ArrayList writeObject, readObject for serialization and deserialization. elementData is modified in order to avoid transient ArrayList expansion (1.5) result in waste of space
  1. Serialization elementData when data is written to the ObjectOutputStream
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();
        }
    }
  1. Deserialization time will be read from the ObjectInputStream
private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

Third, the constructor

  • Specified capacity
    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);
        }
    }
  • default
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • ArrayList(Collection<? extends E> c)
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //空对象数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

Four, ArrayList how expansion

    public boolean add(E e) {
        //确保elementData数组的大小
        ensureCapacityInternal(size + 1);
        //在结尾处添加元素
        elementData[size++] = e;
        return true;
    }

The above is the source add (E e) of the method, before the additive elements will be called ensureCapacityInternal (size + 1); to ensure that the size of the array elementData.

    private void ensureCapacityInternal(int minCapacity) {
        // 判断元素数组是否为空数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //minCapacity最少=DEFAULT_CAPACITY=10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
  • Wherein ensureCapacityInternal source elementData fragment is first determined whether the reference is a non-empty array constructor, if so, Math.max () takes a large value is assigned to be minCapacity, the minimum is 10 (default capacity). Then, call ensureExplicitCapacity:
    private void ensureExplicitCapacity(int minCapacity) {
        // List结构性修改加1
        modCount++;
        //minCapacity大于elementData数组长度
        if (minCapacity - elementData.length > 0)
            //增长
            grow(minCapacity);
    }
  • ensureExplicitCapacity in modCount record number of structural changes List (structural changes during iteration may cause erroneous results).
  • Then, if minCapacity greater than the length of the array is called Grow elementData (minCapacity) growth function
    
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //oldCapacity >> 1右移一位,这里相当于扩容1.5倍
        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);
    }

The above expansion process oldCapacity >> 1 show elementData.length right one, the capacity retention after expansion is 1.5 times the original volume

Fifth, the main function

remove () function
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);
        //需要移动的元素个数
        int numMoved = size - index - 1;
        //删除的不是最后一个元素
        if (numMoved > 0)
            //index后的元素都向前移动一位
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        //size减一,释放引用,方便垃圾回收器进行垃圾回收
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
  • The number of elements remove (int index) calculation method will first need to move, after the index elements are moved forward one (call System.arraycopy way to move), then size minus one, assigned to null to release references, convenient garbage collector garbage collection.

    Under single-threaded environment, the right to delete elements, you should use iterator () iterator remove elements.

For example, to delete the collection "a"

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            if ("a".equals(iterator.next())) {
                iterator.remove();
            }
        }

Or use a lambda expression

list.removeIf("x"::equals);
set () function, will be replaced by the new value and return the old value.
    public E set(int index, E element) {
        //检查索引
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        //返回旧值
        return oldValue;
    }
get () function, to obtain elements
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

Six, ArrayList performance-related

  • In the case where the size of the capacity can be determined ArrayList capacity estimate as possible, calls the constructor public ArrayList (int initialCapacity) specified size, avoid the performance overhead caused by automatic expansion.
  • Use trimToSize () internal ArrayList array size is reduced to the actual size, in order to save space
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

Guess you like

Origin www.cnblogs.com/tangquanbin/p/10958315.html