ArrayList source code analysis and overall analysis
1) Expansion code
For the above two articles, click the details directly. This article mainly analyzes the capacity expansion mechanism and how the ArrayList is expanded?
/** * Default initial capacity. * Default initial capacity */ private static final int DEFAULT_CAPACITY = 10;
private void ensureCapacityInternal(int minCapacity) { //Judge whether the initialized elementData is an empty array, that is, it has no length if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //Math.max gets the maximum value, DEFAULT_CAPACITY=10; minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } /** *Judge whether the current ArrayList needs to be expanded **/ private void ensureExplicitCapacity(int minCapacity) { //Fast error reporting mechanism modCount++; //If the minCapacity is greater than the length of the actual elementData, it means that the length of the elementData array is not enough. If it is not enough, increase the length of the elementData if (minCapacity - elementData.length > 0) grow(minCapacity); }
2) minCapacity really understands
When is the real expansion? That must be mincapacity - elementData Length > 0 means that the length of elementData itself is not enough.
The minCapacity size is directly related to the add call. There are two situations:
- When add (E) is called, minCapacity=size + 1. When adding for the first time, that is, minCapacity=1, the initial value is determined to be 10, so the final math The minCapacity obtained by Max is also 10;
- add(int index, E element) calls the parameterized structure to initialize 'the minimum array capacity required after adding elements' as the actual number of elements after adding elements
3) Growth core expansion logic
//Maximum capacity private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //Increase the capacity to ensure that it can accommodate at least the number of elements specified by the minimum capacity parameter. //Parameter: minCapacity – minimum capacity required private void grow(int minCapacity) { //Capacity size before assignment int oldCapacity = elementData.length; //New capacity = 1.5 times the previous capacity int newCapacity = oldCapacity + (oldCapacity >> 1); //Capacity after expansion < previous capacity if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //Capacity after expansion > maximum capacity if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: //Arrays. Capacity expansion strategy of copyof space for time elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
Call arrays The copyof method points the elementData array to the contiguous space of newCapacity when the memory space is new
And copy the data of elementData to the new memory space
4) Why is the maximum array size of ArrayList integer MAX_ VALUE-8?
Reference article: Please click here
2 ^ 31 = 2147483648, as an array with 8 bytes storage size
5) Code debugging and verification of expansion logic
We wrote an article about reflection before:
How to get attribute values using reflection
For elementData, we also obtain it through reflection.
The test demo is as follows:
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); // Define an array and put 21 values into the instruction to see how to dynamically expand the capacity? for (int i = 0; i < 21; i++) { list.add(i); // Without adding an element, the elementData value is obtained through the reflection mechanism and printed Class<ArrayList> arrayListClass = ArrayList.class; try { Field field = arrayListClass.getDeclaredField("elementData"); field.setAccessible(true); Object[] objects = (Object[]) field.get(list); System.out.println("The first" + i + "After expansion of elements elementData: " + objects.length); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } }
Output result:
elementData after expansion of the 0th element: 10
elementData after the expansion of the first element: 10
elementData after the expansion of the second element: 10
elementData after capacity expansion of the third element: 10
elementData after capacity expansion of the fourth element: 10
elementData after capacity expansion of the fifth element: 10
elementData after capacity expansion of the 6th element: 10
elementData after capacity expansion of the seventh element: 10
The 8th element after the expansion of elementData:
elementData after capacity expansion of the 9th element: 10
elementData after capacity expansion of the 10th element: 15
elementData after capacity expansion of the 11th element: 15
elementData after capacity expansion of the 12th element: 15
elementData after capacity expansion of the 13th element: 15
elementData after capacity expansion of the 14th element: 15
elementData after capacity expansion of the 15th element: 22
elementData after capacity expansion of the 16th element: 22
elementData after capacity expansion of the 17th element: 22
elementData after capacity expansion of the 18th element: 22
elementData after capacity expansion of the 19th element: 22
elementData after capacity expansion of the 20th element: 22
We can clearly see the expansion
- When the list size is < 10, the capacity is the default value, that is, 10
- When 10 = < list < 15, the capacity is 1.5 times, that is, 10 * 1.5 = 15
- When 15 = < list < 21, the capacity is expanded by 15 times, that is, 15 * 1.5 = 22.5, and the integer is 22