Arrays
One-Dimensional Arrays
Understand contiguous memory layouts, primitive vs reference object arrays, and runtime bounds checks in Java.
Interview: Tests array heap allocations, implicit length attributes, initialization styles, and bounds-checking overheads.
In Java, an array is a dynamically allocated container object that holds a fixed number of values of a single data type. Elements are stored in contiguous memory addresses, enabling index-based constant time access (O(1)). Regardless of whether they hold primitives or reference types, all arrays are heap-allocated objects in Java.
Core Idea
Arrays are container objects. A reference to the array is kept on the stack, while the array data itself is stored on the heap.
Why It Matters
Primitive arrays store raw values contiguously, whereas reference arrays store pointer references. This distinction impacts cache locality and memory overhead.
Interview Lens
Focuses on memory representations, the implicit length variable, bounds check overrides, and initialization syntax differences.
Memory Layout
When an array is initialized, the JVM allocates contiguous slots on the heap.
- Primitive Arrays (e.g.,
int[]): The elements are stored directly inside the array slots contiguously. E.g., anint[5]array allocates exactly20 bytes(5 * 4 bytes) plus the object header overhead. - Reference Arrays (e.g.,
String[]orInteger[]): The array slots store 32-bit or 64-bit reference addresses (pointers) pointing to separate objects on the heap. This layout introduces pointer chasing overhead, reducing cache locality.
The Array Header
Since arrays are objects, they contain an object header (typically 12 to 16 bytes depending on JVM bit compression). Inside the header, the JVM stores:
- Mark Word: Stores lock state, hash code, and GC age bits.
- Klass Word: Points to the Class metadata representing the array type (e.g.,
[Iforint[],[Ljava/lang/String;forString[]). - Length Field: An immutable 32-bit integer that stores the array capacity. This is accessed via the public field
array.length.
Runtime Bounds Check
Java enforces memory safety. For every array index access, the JVM checks the index value against the array's internal length field. If the index is negative or greater than or equal to the length, a runtime ArrayIndexOutOfBoundsException is thrown. This check prevents buffer overflow vulnerabilities common in languages like C/C++.
Common Pitfalls
- Confusing length with length(): Writing
array.length()(with parentheses) instead ofarray.length. The length parameter is a public field on array objects, not a method. - Off-by-One Bounds: Attempting to access index
array.lengthinstead ofarray.length - 1. - Null Reference Array Slots: Instantiating a reference array (e.g.,
Object[] arr = new Object[5]) and trying to access an element's method before initializing that slot (throws NullPointerException because slots defaults tonull).
Best Practices
- Use arrays instead of ArrayLists in highly recursive or compute-heavy loops to avoid autoboxing and dynamic resizing overhead.
- Initialize array elements immediately after allocation if you are using reference arrays.
- Use standard arrays for fixed-size static mapping collections.
Interview-Relevant Information
Q1: Are arrays in Java allocated on the stack or on the heap?
Answer: All arrays in Java, whether primitive arrays or object arrays, are objects and are allocated on the heap. The variable holding the array (e.g., int[] arr) is a reference variable, which is stored on the stack if declared inside a local method scope.
Q2: What is the heap memory difference between an int[] array of size 5 and an Integer[] array of size 5?
Answer: An int[] stores raw 32-bit values directly in contiguous heap addresses. An Integer[] stores five reference addresses (pointers) in contiguous heap slots. Each reference pointer points to a separate Integer object located elsewhere on the heap, creating 5 additional objects with object headers, leading to significant memory and GC overhead.
Quick Checklist
Can you describe the header layout of an array, explain why arrays are always heap objects, differentiate primitive from reference array structures in memory, and manage bounds exceptions? If yes, you understand standard 1D arrays.
Use Cases
Caching precomputed calculations (like factorial arrays) to facilitate constant-time numeric retrieval.
Structuring processing buffers where allocation sizes remain fixed and immutable.
Common Mistakes
Attempting to call length() as a method on array objects.
Iterating up to array.length inclusive, triggering IndexOutOfBounds exceptions.