ArrayList source code (based on Java1.8), arraylistjava1.8
ArrayList is implemented based on arrays, that is, operations on the variable Object [] series, encapsulated as commonly used add, remove, indexOf, and contains are essentially performed on arrays through the size counter.
The add method and toArray are also completed using the Arrays tool class.
Another interesting thing is that the add expansion method ensureCapacityInternal () increases the capacity by 50%,
Because the underlying array is immutable, add uses the Arrays tool to copy the expanded array and overwrite the current array.
The length of the preset set is the optimal operation. The principle is only available in the source code. By default, the ArrayList constructor defines the length of the internal array as 10. When the list exceeds the specified set, arrayList automatically scales up,
The expansion method is to use Arrays. the copyOf method re-constructs a new array, and then copies all the data in the old array to the new array, re-generates it, And then copies the array, which consumes a huge amount, this also leads to the inherent disadvantage of ArrayList, And it is slow to insert and delete elements.
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; // non-private to simplify nested class access private int size;
In the source code, we can see that ArrayList inherits the abstract class AbstractList and implements the List interface, RandomAccess, Cloneable, Serializable and Other interfaces, which are mainly used for identification and does not play a major role.
DEFAULT_CAPACITY = 10 is the default initialization length of the set. We often use the new ArrayList <> () structure to create an Object [] array with a length of 10.
Size indicates the counter and records the length of the current array.
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); } } /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
In the constructor code, see the two most common constructor. The constructor with the initialCapacity parameter allows the variable to create an array of the corresponding length, if initialCapacity = 0, the value is directly assigned to an empty array Object [] elementData = {};
If there is no parameter constructor below, an empty list with a capacity of 10 will be initialized directly.
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); }
The above method automatically expands the array capacity. This method is called every time an element is added to ensure that the length of the set is sufficient. The most interesting of the above Code is that two lines
NewCapacity = oldCapacity + (oldCapacity> 1). Each time the capacity is increased to 50% of the current capacity, the Capacity Expansion here is fixed, which is different from the load factor of HashMap.
Call Arrays. copyOf () to take the old array content and the new length as parameters, create a new Object [] array, and copy the elements of the original array to the new array.
Because the array length is immutable, the method here is to create a new array and then copy the elements, which is also the lowest performance of ArrayList.
public int size() { return size;}public boolean isEmpty() { return size == 0;}public boolean contains(Object o) { return indexOf(o) >= 0;}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;}public Object[] toArray() { return Arrays.copyOf(elementData, size);}E elementData(int index) { return (E) elementData[index];}
The commonly used size, isEmpty, contains, and indexOf are also a series of cyclic judgment operations on Object [].
public E get(int index) { rangeCheck(index); return elementData(index);}public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true;}public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); 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;}
The get method also refers to obtaining an Object from the Object [] array through subscript, and then transforming the Object-> E
Add an element at the end of add to determine whether the capacity is sufficient. Then, add elementData [size ++] = e to the end of the array. size indicates the length of the array.
The remove method also finds the subscript by repeating equals matching, and then deletes the subscript,-size, minus the counter length, without actually reducing the array length.
The clear method is the same. Set the values of the array to null, and then size = 0;
Summary:
Based on the source code analysis of the key parts of ArrayList, and familiar with the principle of ArrayList, we can draw a conclusion: