Collections Framework
ArrayList
Analyze ArrayList internal structures, array copy mechanics, resizing logic, and random access execution.
Interview: Focuses on array growth factor (1.5x), System.arraycopy usage, O(1) indexing, and initial capacity optimization.
An ArrayList is a resizable-array implementation of the List interface. It is backed by a native heap array that dynamically grows when elements exceed the array's capacity.
Random Access
Implements RandomAccess, providing constant-time O(1) lookup complexity for elements using integer index keys.
Dynamic Resizing
When capacity is reached, ArrayList allocates a new array of size oldCapacity + (oldCapacity gg 1) (1.5x size) and copies elements using native code.
Insertion Cost
Adding to the end is amortized O(1). Inserting or deleting from the middle takes O(N) time due to array copy operations.
Internal Growth & Array Copy
Understanding the resizing mechanism is key to optimizing application performance:
- The default initial capacity is 10 (allocated lazily on the first element addition).
- When the array fills up, a new array is calculated:
newCapacity = oldCapacity + (oldCapacity >> 1). - JVM invokes
Arrays.copyOf, which calls nativeSystem.arraycopyto transfer elements into the new array. - The old array is dereferenced and cleaned up by GC.
Common Pitfalls
- Frequent Resizing: Adding millions of elements to an ArrayList initialized with default capacity, triggering dozens of array allocations and garbage collections.
- Inserting at index 0: Repeatedly calling
list.add(0, item)in a loop, which forces shifting all existing array elements, causingO(N²)aggregate latency.
Best Practices
- Pre-size initial capacity: Always specify the expected size in the constructor (e.g.
new ArrayList<>(expectedSize)) when size is predictable. - Use trimToSize(): Invoke
list.trimToSize()after collection population to reduce unused capacity elements and conserve memory.
Interview-Relevant Information
Q1: How does ArrayList calculate its new capacity on expansion?
Answer: It increases the current capacity by approximately 50% using bit-shifting arithmetic: int newCapacity = oldCapacity + (oldCapacity >> 1).
Q2: Why does ArrayList implement RandomAccess?
Answer: RandomAccess is a marker interface. It signals that the collection supports constant-time (O(1)) element retrieval by index. This allows algorithms to choose index loops over iterators for performance.
Quick Checklist
Can you state the default capacity of an empty ArrayList, calculate the size after expansion, and explain why inserting at the front is expensive? If yes, you understand ArrayList.
Use Cases
Storing and fetching data records that require rapid indexing lookup operations.
Building memory-cached database rows where capacity sizes are predictable.
Common Mistakes
Initializing empty collections when storing millions of data structures.
Inserting elements at index 0 repeatedly in high-throughput data pipelines.