What is an ArrayList
ArrayList is an expandable array Resizable-array that implements all the methods of the List interface.
Here are a few points from a simple description of ArrayList
- ArrayList is an array, but unlike general arrays, it is scalable and has a fixed capacity.
- ArrayList implements the List interface, so ArrayList implements the basic methods that List contains (add, delete, insert, and so on).
10 things ArrayList needs to know
1.ArrayList is implemented internally through arrays
The internal implementation of ArrayList is through an array of objects
transient Object[] elementData
2. The execution time of the ArrayList add operation is fixed
The ArrayList add() method essentially implements adding an element elementData[size++] = el at the end of the array, so the time complexity of execution is fixed O(1), and adding n elements is O(n)
3. In addition to the add method, other operations such as insertion and deletion are linear.
Because it is essentially an operation on an array, when inserting or deleting data in the array, the array needs to be shifted first. When inserting, the data after the insertion point needs to be moved all backwards. When deleting, the data after the deletion node needs to be moved all forward with O(n) operation time complexity.
4. Thread security issues
ArrayList is thread insecure when threads modify it in a multithreaded situation.Thread security issues depend on how they are applied.
5. About capacity expansion
ArrayList has its own automatic scaling mechanism and can also be scaled up manually when data size is expected to be processed
1. Automatic capacity expansion
When an ArrayList adds an element (add, addAll operation), it first detects if the current internal array elementData[] is large enough to add a new element, or if it is not, it expands. ArrayList has a maximum capacity of Integer.MAX_VALUE. The flow of automatic expansion calls is as follows
public boolean add(E e) { // Automatically expands and records the number of element modifications, mainly for concurrent modification errors ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // Returns the larger of an array size value of minCapacity and the default DEFAULT_CAPACITY private static int calculateCapacity(Object[] elementData, int minCapacity) { // If it is an empty array, it is created by a new ArrayList() if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // Default size is DEFAULT_CAPACITY = 10 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
Actual expanded capacity segment
private void ensureExplicitCapacity(int minCapacity) { modCount++; // Compare the size returned by the above method with the current elementData size to determine if an extension is required if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // Specific expansion code int oldCapacity = elementData.length; // Capacity always increases by about 1.5 times after capacity expansion by 0.5 times before capacity expansion int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // If the maximum number limit is exceeded after expansion, it is handled by hugeCapacity() 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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
2. Manually expand capacity or specify initial capacity
Manual expansion of ArrayList mainly calls the ensureCapacity(int minCapacity) method, in addition to specifying the initial capacity when creating an ArrayList
Create a new ArrayList <> (initialCapacity) with its implementation specified directly
public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // Create an array of the specified capacity this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
Enlargement during processing by the ensure Capacity (int minCapacity) method generally occurs when the initial capacity is found to be inadequate for the current data requirements during processing, and to avoid waste of resources during automatic expansion, since an array copy occurs each time an automatic expansion occurs.
public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0: DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
3. Finally, look at the array replication at capacity expansion, which is done using the Arrays.copyOf(origin,newLenght) method
public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); } // Specific Copy Code public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); // Copy data from old arrays to new arrays System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
6. Questions about how ArrayList is passed.
When an ArrayList is passed in a method, it passes a reference to an object. When a method modifies an ArrayList, the modification is reflected in all the places that reference the ArrayList. No matter how many passes, it refers to data in the same memory area. Therefore, if you want to ensure that the content remains unchanged during the transfer, you should clone one copy of the (using the clone () method of the ArrayList) for transfer (It is important to note that the Collections.copy(dest,src) method can be used for deep cloning, depending on the needs.
7. The relationship between capacity and size of ArrayList
If you're looking for a relationship between them, it might be size = number of elements <= capacity = capacity size.Size reflects how much data is stored in the current array, while capacity reflects the capacity of an array inside ArrayList.It is not customary to think of capacity as both size
8. Selectivity of ArrayList and LinkedList
Why are ArrayList s and LinkedList s selective because they have different performance when get ting, add ing, removing?
ArrayList is an internal implementation that is an array, and the time complexity when accessing randomly is O(1) knowing that the index is immediately accessible, while its insertion and deletion operations are relatively cumbersome and require linear time complexity for shift operations.
LinkedList is a two-way joined table Doubly-linked, with O(1) time complexity for insertion and deletion, but the index (taking the value on the index bit) needs to be traversed from the header or tail.
So which one you choose depends entirely on whether you want to do random access or add or delete more elements.
9. Why elementData uses transient s to decorate it
The transient s keyword prevents object serialization, so why do you want to prevent elementData serialization? That's because elementData is an array, and it doesn't hold values at every location in the array. There may only be 10 objects in an array with a capacity of 10,000.Therefore, it cannot be serialized, and the methods of writeObject and readObject are overridden in ArrayList to control the serialization of ArrayList.
10. What is the use of ArrayList to implement the RandomAccess interface
The RandomAccess interface is a markup interface and does not define any methods. ArrayList implements it as a markup ArrayList that supports the fast random access feature!
Not Ended to Continue