Interpretation of ArrayList source code
attribute
private static final int DEFAULT_CAPACITY = 10;//Default initialization space private static final Object[] EMPTY_ELEMENTDATA = {};//Empty array for empty object initialization private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; //Storage array, non private simplifies nested class access private int size;//Amount of data actually stored protected transient int modCount = 0;//The number of times the collection has been operated. If the number of times does not match, the ConcurrentModificationException() will be thrown;
Construction method
Construction method of setting initial space size
public ArrayList(int initialCapacity) { if (initialCapacity > 0) {//If it is greater than 0, an Object array of corresponding length will be constructed this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) {//Assign empty array object directly when equal to 0 this.elementData = EMPTY_ELEMENTDATA; } else {//Throw an exception if it is less than 0 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
Nonparametric construction method
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//Assign empty array objects directly }
The construction method of parameter of set subclass
public ArrayList(Collection<? extends E> c) { elementData = c.toArray();//Parameter c is the class that implements Collection, and toArray is the method defined for the Collection interface if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class)//The return type of Arrays.copyOf depends on the type of the first parameter. To prevent Arrays.copyOf from not returning Object [] type data, see https://bugs.openjdk.java.net/browse/JDK-6260652 for bugs elementData = Arrays.copyOf(elementData, size, Object[].class);//Note here that only the actual data length is copied } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA;//If the length of the c parameter set is 0, then the elementData is assigned to an empty array object } }
Basic method
Trimtosize elementdata length trim to actual storage data length
public void trimToSize() { modCount++;//Operand +1 if (size < elementData.length) {//If the actual storage quantity is less than the length of elementData elementData = (size == 0) ? EMPTY_ELEMENTDATA//If the actual storage is 0, then the elementData assignment is an empty array object : Arrays.copyOf(elementData, size);//Otherwise, copy the data of the actual storage length } }
Ensure that the elementData can hold at least minCapacity data
public void ensureCapacity(int minCapacity) { if ( minCapacity > elementData.length//The minimum capacity is greater than the current elementData length && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA&& minCapacity <= DEFAULT_CAPACITY)//elementData is not equal to an empty array object and the minimum capacity is greater than the default space (10) ) { modCount++;//Operand +1 grow(minCapacity);//Expand the array if the condition is met } }
grow extended array
private Object[] grow() { return grow(size + 1);//Expand according to the actual storage data amount + 1 }
grow(int minCapacity) extended array
private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));//Copy array, return with length of newCapacity(minCapacity) }
newCapacity(int minCapacity) returns a capacity at least as large as the given minimum capacity
private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length;//Get old elementData length int newCapacity = oldCapacity + (oldCapacity >> 1);//The new length is 1.5 times the old one if (newCapacity - minCapacity <= 0) {//If the new length is smaller than the minimum capacity if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) return Math.max(DEFAULT_CAPACITY, minCapacity);//If elementData is empty, return the larger of 10 and minimum capacity if (minCapacity < 0) // overflow throw new OutOfMemoryError();//Negative minimum capacity not allowed return minCapacity;//If the new length is smaller than the minimum capacity, return the minimum capacity directly } return (newCapacity - MAX_ARRAY_SIZE <= 0)//If the new length is smaller than the maximum length, the new capacity is returned, otherwise the return value of hugeCapacity(minCapacity) is returned ? newCapacity : hugeCapacity(minCapacity); }
hugeCapacity(int minCapacity) returns large capacity
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError();//Negative minimum capacity not allowed return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE//If the minimum capacity is greater than the maximum value of Integer, return the maximum value of Integer : MAX_ARRAY_SIZE;//Otherwise, return Max array size (max array size = integer.max value - 8;) }
size returns the number of data actually stored
public int size() { return size; }
isEmpty determines whether the actual stored data is empty
public boolean isEmpty() { return size == 0; }
contains determines whether an element exists
public boolean contains(Object o) { return indexOf(o) >= 0; }
indexOf gets an element location
public int indexOf(Object o) { return indexOfRange(o, 0, size); }
indexOfRange(Object o, int start, int end) range to query the location of target data in the collection
int indexOfRange(Object o, int start, int end) { Object[] es = elementData; if (o == null) {//If the target data is empty for (int i = start; i < end; i++) {//Loop from start to end if (es[i] == null) { return i;//If the data is null, the corresponding subscript is returned } } } else {//Target data is not empty for (int i = start; i < end; i++) {//Loop from start to end if (o.equals(es[i])) {//It's important to call the equals method of the target function return i; } } } return -1; }
lastIndexOf(Object o) finds the last occurrence of an element
public int lastIndexOf(Object o) { return lastIndexOfRange(o, 0, size); }
Last indexofrange (object o, int start, int end) query element last occurrence (i.e. reverse first occurrence)
int lastIndexOfRange(Object o, int start, int end) { Object[] es = elementData; if (o == null) {//If the target data is empty for (int i = end - 1; i >= start; i--) {//From end-1 if (es[i] == null) { return i; } } } else { for (int i = end - 1; i >= start; i--) { if (o.equals(es[i])) {//It's important to call the equals method of the target function return i; } } } return -1; }
Hang in the air...