skip to content

Multidimensional and Jagged Arrays

Java has no rectangular arrays, only arrays of arrays, so rows may have different lengths or not exist at all. Interviewers ask this to check you understand the memory layout implications versus a true 2D block.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

In Java, what is a two-dimensional array really, and why does Java have no true rectangular multidimensional arrays?

level: juniorimportance: must knowfreq 70%

answer

  1. int[][] = array of int[] references
  2. a.length = rows, a[i].length = that row
  3. two dereferences per a[i][j]
  4. rows are independent heap objects
  5. no contiguous rows×cols block like C

basics

~20 s

A Java 2D array is an array whose elements are themselves arrays (an array of arrays). Java has no single block of rows-by-columns; each row is a separate array object, so rows can even have different lengths.

solid answer

~40 s

Java has no genuine rectangular multidimensional array type. What looks like a 2D array, int[][], is really a one-dimensional array whose elements are references to other one-dimensional int[] arrays. So a[0] and a[1] are independent array objects, possibly at unrelated places in memory and possibly of different lengths. a.length gives the number of rows; a[i].length gives that particular row's length. This array-of-arrays model is why jagged arrays exist for free and why you index with a[i][j] (first pick the row reference, then index into it). It contrasts with languages like C or Fortran that store a true contiguous N-dimensional block. The trade-off: flexibility and easy sub-array sharing, but an extra pointer dereference per dimension and worse cache locality.

go deeper

for a junior

Knows a 2D array is an array of arrays and can use a[i][j], a.length, a[i].length correctly.

for a middle

Explains the two-dereference indexing, that rows are independent objects, and that rows can differ in length.

for a senior

Discusses cache-locality and performance implications versus a flattened 1D layout and when to choose each.

for a principal

Frames the array-of-arrays decision as a language design trade-off (flexibility/aliasing vs. contiguity), and guides teams on flattening, memory layout, and JIT/bounds-check behavior in hot numeric code.

## The core idea An **array** is a fixed-size, indexed container of values of one type. A **multidimensional array** conceptually is a grid (2D), cube (3D), etc. Many languages (C, Fortran) implement a 2D array as one **contiguous** block of memory of size rows×columns, with the compiler computing the address `base + (i*columns + j)*elementSize`. That is a *true rectangular array*: every row is guaranteed the same length and laid out back-to-back. **Java does not have this.** In Java, the type `int[][]` literally means "an array whose element type is `int[]`" — an **array of arrays**, also called a *nested* or *jagged-capable* array. ## What that means concretely Write `int[][] a = new int[3][4];`. Java creates: - one **outer** array of length 3 whose element type is `int[]` (it holds 3 *references*), - three **inner** `int[]` arrays, each of length 4, - and stores a reference to each inner array in the outer array's slots. So `a` is a reference to the outer array. `a[0]`, `a[1]`, `a[2]` are each a reference to a separate `int[]` object. These three inner arrays are independent heap objects and are **not** required to sit next to each other in memory. Indexing `a[i][j]` is two steps: (1) read `a[i]` — follow a reference to get the i-th inner array; (2) index `[j]` into that inner array. That is **two pointer dereferences**, versus one address computation in a contiguous layout. ## Why "no true rectangular array" Because each row is an independent object, nothing forces the rows to be equal length. `new int[3][4]` happens to make them all length 4, but you can replace any row: `a[1] = new int[10];` is legal. The "rectangle" is only a convention, not a language guarantee. The lengths are queried per level: `a.length` is the number of rows (the outer length); `a[i].length` is the length of row i. ## Consequences 1. **Jagged arrays are free** — rows of different lengths are the natural case, not a special feature (see the dedicated jagged-array question). 2. **Sub-arrays can be shared/aliased** — `int[] row = a[1];` makes `row` and `a[1]` the same object; mutating one is seen through the other. 3. **Performance** — extra indirection plus rows scattered on the heap means worse **cache locality** (the CPU caches contiguous memory; jumping between far-apart rows causes more cache misses) than a flat contiguous array. 4. **Initialization** — a freshly `new int[3][4]` array has every element at the default (`0` for int, `null` for references, `false` for boolean, etc.). ## Higher dimensions The pattern recurses: `int[][][]` is an array of (arrays of (arrays of int)). `new int[2][3][4]` builds one outer length-2 array, two length-3 arrays, and six length-4 arrays — 9 array objects in total. ## When it matters For most code the convenience wins. For numeric-heavy, performance-critical work, practitioners often **flatten** to a single `int[]` of size rows*cols and index manually as `data[i*cols + j]` to recover the contiguous, cache-friendly C-style layout.

  • How many array objects does new int[2][3][4] create in total?
    Nine: one outer length-2 array, two length-3 arrays it points to, and six length-4 int arrays (2×3) at the bottom — 1 + 2 + 6 = 9.
  • How would you get a true contiguous layout for performance?
    Flatten to a single 1D array of size rows*cols and index as data[i*cols + j], which restores C-style contiguity and cache locality.

saying these in an interview costs you the question

  • Saying Java stores 2D arrays as one contiguous rows×columns block
  • Assuming a.length gives the column count or total element count
  • Believing all rows must be the same length
  • Thinking a[i] is a value rather than a reference to a separate array

context

open as a page

How does Java handle partial allocation and default initialization across the dimensions of a multidimensional array?

level: juniorimportance: should knowfreq 40%

basics

~20 s

new int[3][4] allocates every level and fills all cells with 0. new int[3][] allocates only the outer array, leaving each row null until you assign it. You may leave trailing dimensions empty but not skip an earlier one.

open as a page

How should you correctly iterate over a multidimensional or jagged array in Java, and what bugs arise from doing it wrong?

level: middleimportance: should knowfreq 45%

basics

~10 s

Loop the outer array with a.length, and for each row loop with that row's own a[i].length. Using a single fixed width or assuming rows are non-null causes out-of-bounds errors or NullPointerExceptions.

open as a page

What is a jagged (ragged) array in Java, and how do you create one with rows of differing length?

level: middleimportance: should knowfreq 55%

basics

~10 s

A jagged array is a 2D array whose rows have different lengths. Because Java's 2D arrays are arrays of arrays, you just create the outer array first, then assign each row its own length.

open as a page

Compared with a flat one-dimensional array, what are the memory-layout and performance characteristics of Java's array-of-arrays, and when would you flatten?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Java's 2D array scatters each row as a separate heap object, so reaching an element needs an extra pointer hop and gives worse cache locality. For hot numeric code you can flatten to one 1D array and index as data[i*cols+j] for contiguous, cache-friendly access.

open as a page