skip to content

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

level: juniorimportance: should knowfreq 40%

answer

  1. new int[3][4]: all allocated, all 0
  2. new int[3][]: outer only, rows null -> NPE
  3. trailing dims may be empty; earlier ones may not
  4. new int[][4] = compile error
  5. object cells default to null, not empty

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.

solid answer

~40 s

When you write new int[3][4], Java allocates the outer array and all inner rows, initializing every element to the type's default (0 for int, null for references, false for boolean, etc.). When you write new int[3][], only the outer length-3 array is created and each element is null — no rows exist until you allocate them, so accessing a[0].length or a[0][0] throws NullPointerException. This partial allocation is what enables jagged arrays: allocate the outer first, then give each row its own length. The rule for which dimensions you may omit: you can leave any number of trailing dimensions unspecified (new int[3][] or new int[3][][]), but you cannot specify a later dimension while skipping an earlier one (new int[][4] is a compile error). Object arrays like String[3][3] fully allocate but default every element to null.

code

java · 11 lines
java
int[][] full = new int[3][4];     // all 12 ints = 0, no nulls
int zero = full[2][3];            // 0
int len  = full[1].length;        // 4

int[][] part = new int[3][];      // outer only; rows are null
int rows = part.length;           // 3
// int bad = part[0].length;      // NullPointerException (row 0 is null)
part[0] = new int[2];             // now row 0 exists, elements = 0

// new int[][4];                  // COMPILE ERROR: earlier dimension skipped
String[][] names = new String[2][2];  // allocated, but every cell is null

go deeper

for a junior

Knows new int[3][4] zero-fills everything while new int[3][] leaves rows null, and that you must allocate rows before use.

for a middle

States the dimension-omission rule, default values per type, and why object cells are null; uses partial allocation to build jagged arrays.

for a senior

Connects partial allocation/defaults to the array-of-arrays model and to common NPE/AIOOBE bugs, and designs around nullable rows.

for a principal

Establishes conventions for safe construction of multidimensional structures and clear API contracts about which dimensions/rows may be unallocated.

## Default initialization recap When Java creates an array, every element is set to the **default value** for its type — you never get garbage: - numeric types (`int`, `long`, `double`, …): `0` / `0.0` - `boolean`: `false` - `char`: `''` - reference types (`String`, any object, **and `int[]`**): `null` This matters for multidimensional arrays because the *outer* array's element type is itself an **array type** (a reference type), so an unallocated row defaults to `null`. ## Full allocation: `new int[3][4]` Allocates everything: - outer array length 3, - three inner `int[]` of length 4, - all 12 ints set to `0`. You can immediately read `a[i][j]` (it's `0`) and `a[i].length` (it's `4`). No nulls. ## Partial allocation: `new int[3][]` Allocates **only** the outer array: - outer array length 3, - each element is `null` (no inner arrays exist). `a.length` is 3, but `a[0]` is `null`. Reading `a[0].length` or `a[0][0]` throws **`NullPointerException`** until you do `a[0] = new int[...]`. This is precisely the mechanism that lets you build **jagged** arrays: allocate the outer, then size each row independently. ## The dimension-omission rule You may leave **trailing** dimensions unspecified, but the **leading** (and any earlier) dimensions must be sized, with no gaps: - `new int[3][]` — legal (outer sized, rows null) - `new int[3][][]` — legal (outer sized, the rest null) - `new int[][4]` — **compile error**: you cannot specify a later dimension while leaving an earlier one empty - `new int[3][4][]` — legal (first two levels allocated, deepest level null) The intuition: allocation proceeds outer-to-inner; you can stop early (leave inner levels null) but you cannot skip a level and then resume. ## Object element types `new String[3][3]` allocates both levels but, because the element type is a reference type, every `String` slot defaults to `null` (not `""`). Same for any object type: the cells exist but reference nothing until assigned. (Contrast `int[3][3]`, whose cells are `0`.) ## Initializer shortcuts Array initializers allocate and fill in one step and infer lengths from braces: ```java int[][] a = { {1, 2}, {3} }; // sizes inferred, jagged, no nulls String[][] s = { {"a"}, {"b","c"} }; ``` ## Why this design Partial allocation plus per-level defaults is the direct consequence of the array-of-arrays model: the outer array just holds references, which default to null, and you fill them in when (and at whatever size) you choose. It costs you the null-row footgun in exchange for full control over each row's existence and length.

  • What is each element of new String[2][2] before you assign anything?
    null. Both levels are allocated, but since the element type is a reference type, every String slot defaults to null (not an empty string).
  • Why is new int[3][] useful if its rows are null?
    It lets you build jagged arrays: allocate the outer array first, then give each row its own length with a[i] = new int[someLength].

saying these in an interview costs you the question

  • Thinking new int[3][] zero-fills the rows like new int[3][4]
  • Expecting String cells to default to empty string instead of null
  • Believing new int[][4] compiles
  • Assuming array elements could contain uninitialized garbage

context