Fundamentals 13 min read

Deep Dive into Java ArrayList: Implementation, Thread Safety, and Common Operations

This article provides an in‑depth explanation of Java's ArrayList, covering its purpose, lack of thread safety, detailed source‑code analysis of fields, constructors and core methods, serialization mechanics, capacity handling, and a simplified hand‑written implementation for interview preparation.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Deep Dive into Java ArrayList: Implementation, Thread Safety, and Common Operations

Introduction

ArrayList is a widely used data‑storage container in Java. Its underlying implementation is an array, allowing storage of any type of element. It is not thread‑safe but offers very high lookup efficiency.

Thread Safety

Operations on an ArrayList consist of two steps—changing the size and manipulating elements—so in a multithreaded environment these actions are not atomic, making ArrayList unsafe for concurrent use.

Source Code Analysis

1. Field Analysis

/**
 * Default initial capacity
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * Empty array used when capacity is zero or for empty‑array replacement
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * Empty array used when no custom capacity is specified
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * The backing array (transient to avoid default serialization)
 */
transient Object[] elementData;

/**
 * Current number of elements in the list
 */
private int size;

/**
 * Maximum array size
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2. Constructor Analysis

When an initial capacity is provided, a new array of that size is allocated. If the capacity is zero, EMPTY_ELEMENTDATA is used. A negative capacity throws IllegalArgumentException . The no‑arg constructor uses DEFAULTCAPACITY_EMPTY_ELEMENTDATA (capacity 10). A constructor that accepts a Collection copies the collection's elements into the backing array, handling the case where toArray() does not return an Object[] .

3. Core Methods

trimToSize()

Reduces the backing array to the actual number of stored elements, freeing unused space.

public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size);
    }
}

clone()

Creates a shallow copy of the list, then clones the backing array to ensure the new list has its own storage.

public Object clone() {
    try {
        ArrayList
v = (ArrayList
) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        throw new InternalError(e);
    }
}

add(E e)

Appends an element to the end of the list, first ensuring enough capacity (size+1) and then storing the element.

public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal(int minCapacity)

Calculates the required capacity and delegates to ensureExplicitCapacity , which grows the array when necessary.

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

grow(int minCapacity)

Expands the backing array by roughly 1.5×, handling overflow and the maximum array size.

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

add(int index, E element)

Inserts an element at a specific position, shifting subsequent elements with System.arraycopy .

public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    size++;
}

remove(int index)

Removes the element at the given index, shifts remaining elements left, clears the freed slot for GC, and returns the removed element.

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;
    return oldValue;
}

Serialization Details

Because elementData is marked transient , ArrayList implements custom writeObject and readObject methods. During serialization only the actual size and the stored elements are written to the ObjectOutputStream , which saves space and time compared to writing the whole backing array.

Advantages and Disadvantages

Advantages: Fast random access and lookup due to array backing; automatic growth (approximately 1.5×) when capacity is exceeded.

Disadvantages: Insertion and deletion in the middle are costly because elements must be shifted; not thread‑safe.

Hand‑written Simplified ArrayList

A minimal implementation suitable for interview practice is provided, demonstrating the essential fields, constructors, add , get , remove , capacity growth logic, and range checks.

public class MyArrayList {
    transient Object[] elementData;
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    private int size;
    // constructors, add, ensureExplicitCapacity, get, rangeCheck, remove, etc.
}

Understanding these internals helps candidates answer interview questions about ArrayList behavior, thread safety, capacity calculations, and custom implementations.

JavaSerializationDataStructurecollectionsArrayListThreadSafetyCodingInterview
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.