What is the fundamental difference between a Java array and an ArrayList, and when would you choose one over the other?
answer
- Array = fixed length, primitives OK, only .length and [i]
- ArrayList = resizable, objects only, full API
- ArrayList is backed by an array internally (grows ~1.5x)
- Primitives in ArrayList get autoboxed (int -> Integer)
- Default to ArrayList; use array for fixed size / primitive perf
basics
~20 sAn array has a fixed size set when you create it and can hold primitives or objects. An ArrayList grows and shrinks automatically and only holds objects. Use an array for a known fixed count; use an ArrayList when the size changes.
solid answer
~40 sA Java array is a fixed-length container declared with a size (new int[10]); that length never changes. It can store primitives (int, double) directly or object references, and exposes only a .length field plus index access. An ArrayList is a resizable list from java.util backed internally by an array; it grows automatically via add() and shrinks via remove(), exposing rich methods (size(), contains(), iterator). ArrayList stores only objects, so primitives are autoboxed (int becomes Integer). Choose an array when the count is fixed and known up front, when you need primitive storage without boxing overhead, or in tight performance/memory code. Choose ArrayList when the size is unknown or changes over time, or when you want the convenience of the Collections API. In everyday application code ArrayList is the default; arrays are the exception.
go deeper
Knows an array is fixed size and an ArrayList resizes; can pick the right one for a simple case and knows ArrayList uses .add()/.size() while an array uses [i] and .length.
Explains array-backing of ArrayList, the ~1.5x growth and copy, autoboxing of primitives into wrappers, and gives concrete selection criteria (fixed vs dynamic, primitive perf).
Quantifies the trade-offs (memory of boxed Integer vs int[], amortized O(1) add, copy cost), and recommends List as the declared type for flexibility while reserving arrays for primitives/hot paths.
Frames the choice in terms of API design and data-structure selection across a codebase: defaulting to interfaces (List), when specialized primitive collections (e.g. third-party IntList) earn their keep, and the maintainability cost of leaking arrays through public APIs.
## What these two things are **An array** is the most basic ordered container built into the Java language itself (not a library class). You create it with a fixed length: ```java int[] numbers = new int[5]; // 5 slots, indexes 0..4 ``` The number `5` is the *capacity and the size at the same time* — an array has exactly that many slots forever. You cannot add a sixth element; you'd have to create a new, bigger array and copy everything over yourself. Arrays can hold **primitives** (`int`, `double`, `boolean`, `char`, …) directly, or they can hold **object references** (`String[]`, `Person[]`). An array gives you only two things: `arr.length` (a field, no parentheses) to ask how many slots it has, and `arr[i]` to read or write slot `i`. **An ArrayList** is a class from the standard library (`java.util.ArrayList`). It is a **resizable list**: you can keep calling `add()` and it grows as needed, and `remove()` makes it smaller. Internally an ArrayList *is itself backed by an array* — when that internal array fills up, ArrayList quietly allocates a bigger one (typically about 1.5x the old size) and copies the elements across. You never see this; from your side it just "grows." An ArrayList exposes a whole API: `size()`, `add()`, `get(i)`, `set(i, value)`, `remove()`, `contains()`, `isEmpty()`, iteration with a for-each loop, and so on. ## The key word: generics and boxing ArrayList is **generic**: you write `ArrayList<String>` or `ArrayList<Integer>`. The `<...>` part is a type parameter that says what kind of element it holds, and the compiler checks it. Generics only work with **reference types** (objects), not primitives. So you *cannot* write `ArrayList<int>`. To store numbers you use `ArrayList<Integer>`, where `Integer` is the **wrapper class** for the primitive `int`. Converting an `int` to an `Integer` object is called **autoboxing** (and back is **unboxing**). It happens automatically: ```java List<Integer> list = new ArrayList<>(); list.add(7); // autoboxing: int 7 -> Integer object int x = list.get(0); // unboxing: Integer -> int ``` Each boxed `Integer` is a separate object on the heap with its own object header, so a million boxed ints take far more memory than `int[1_000_000]`, and boxing/unboxing costs CPU. A raw `int[]` stores the numbers packed tightly with no per-element object overhead. ## When to choose which Use a **raw array** when: - The size is fixed and known up front (e.g., the 12 months of the year). - You are storing **primitives** and care about memory or speed — `int[]` avoids the boxing tax. - You are in low-level / performance-critical code, or interoperating with APIs that take arrays (varargs, `String.split`, `byte[]` for I/O). Use an **ArrayList** when: - The number of elements is unknown or changes over time. - You want the convenience of the Collections API (search, iteration, removal, passing as `List`). - You are writing ordinary business logic — this is the **default** in modern Java. ## A rule of thumb Reach for `ArrayList` (typed as `List`) by default. Drop to a raw array only when you have a concrete reason: fixed size, primitive performance, or an API that demands one. The cost of an array is manual size management and weaker safety; the cost of ArrayList is boxing for primitives plus a small per-object overhead.
- How does an ArrayList grow when it runs out of room?When the internal array is full, ArrayList allocates a new larger array (roughly 1.5x the old capacity), copies the existing elements into it with System.arraycopy, and discards the old one. This happens automatically inside add().
- Why can't you write ArrayList<int>?Generics in Java only accept reference types, not primitives. You must use the wrapper class, ArrayList<Integer>, and ints are autoboxed into Integer objects on insertion.
saying these in an interview costs you the question
- Saying an array can grow or shrink — its length is fixed at creation
- Claiming ArrayList can hold primitives directly (it boxes them)
- Thinking ArrayList is a linked structure — it is array-backed
- Confusing array's .length (field) with ArrayList's size() (method)