Concepts / One-Dimensional Arrays in Java

One-Dimensional Arrays in Java

Java does not have true two-dimensional arrays. A two-dimensional array is an array whose elements are one-dimensional arrays.

  • Programming

Picturing a Grid, and Checking It

Many programmers arrive at Java already picturing a two-dimensional array as a neat grid: rows going across, columns going down, and every cell sitting inside one solid rectangle of storage. That picture is useful, and in many situations it will serve you well. It rests on an assumption, however, and that assumption does not hold in Java. This article examines the assumption directly and replaces it with a more accurate model of what Java does when you write a grid-shaped array.

What do you think happens?

When you create a grid-shaped array in Java, does the language store all of its cells in one solid rectangular block?

  • Yes, all cells sit in one rectangular block

  • No, the grid is built from separate one-dimensional arrays

Reveal answer
Answer:

No. Java does not have true two-dimensional arrays. A two-dimensional array is an array whose elements are one-dimensional arrays.

The grid picture is a helpful everyday model for indexing, but the real structure is an outer array that holds references to row arrays. The rest of this article traces that structure step by step.

Reading the Type int[][]

The type names themselves reveal the real structure. Java follows a simple rule: for any base type, you can form a new type by adding a pair of square brackets, and the result means array of that base type. Start with int[], which means array of int. Now treat int[] as the base type and add brackets again. You get int[][], which means array of int[], or equivalently array of arrays of int. The type name is a construction recipe, and it tells you exactly what the outer array holds.

intbase type: a single int[]first pair: array of int[]second pair: array of int[]wrap as arraywrap again
How does each bracket pair in int[][] map to a level of nesting, and what type does each element have?

Read the type from the inside out. The innermost piece, int, is the element type of the rows. The first pair of brackets turns int into int[], the type of one row. The second pair turns int[] into int[][], the type of the whole grid. So when you see int[][] A, the element of A is a variable of type int[]. Each element of the outer array is itself a variable that refers to one row.

Tracing an Array of Rows

Consider a 3-by-4 array named A. Because A is an array of int[], you can name its three rows as A[0], A[1], and A[2]. Each of these is a complete one-dimensional array of int, and each has four slots. The outer array holds three references, and each reference leads to its own row. The diagram shows this structure.

A (outer array)3 slots, each a rowreferenceA[0]int[4] rowA[1]int[4] rowA[2]int[4] rowrefers torefers torefers to
What does int[][] A contain, and how many separate array objects exist?

Notice what the diagram does not show. It does not show the three rows sitting end to end in one unbroken stretch, and it does not show a single rectangular region. Each row is an independent one-dimensional array that the outer array points to. A useful way to remember this is that the outer array is the table of contents, and the rows are the pages.

java
Output
3
4
7
Notes on the code
  • The outer length counts the rows, which is 3.
  • A[1] is one row, so its length counts the slots in that row, which is 4.
  • A[1][2] first selects the row A[1], then selects slot 2 inside that row.

Two Steps Behind A[1][2]

The source notes that reading and writing cells such as A[1][2] works the way a grid suggests, and most code never needs more than that. Underneath, the lookup happens in two stages. The first bracket, [1], uses the outer array to select a row reference. The second bracket, [2], then indexes into that row to select one element. Because the first stage yields an int[], the second bracket is ordinary one-dimensional indexing on that row.

Worked example

Reading and writing one cell

Given int[][] A = new int[3][4]; what happens when the code executes A[1][2] = 7;?

  1. 1
    Stage one

    Evaluate A[1]. The outer array A returns its element at index 1, which is a reference to the row array for row 1.

  2. 2
    Stage two

    Apply [2] to that row. The row is an int[], so index 2 selects the third slot of that row.

  3. 3
    Assignment

    Store the value 7 in that slot. The outer array was not changed; only the row it points to was changed.

Result

Row 1, slot 2 now holds 7. Rows 0 and 2 are untouched, because each row is a separate array.

Passing a Row to a Method

The source identifies the situation where the row-by-row reality matters. Each row is a value of type int[], so a single row can be handed to any subroutine that asks for an int[] parameter. The row you pass is the row array itself, not a copy of its contents. Inside the method, the parameter refers to the same row array the caller refers to, so a change made through the parameter is visible to the caller.

main()calls fill(grid[1])fill(int[] row)parameter rowrow array for grid[1]row[0] becomes 9passes grid[1]refers to same array
When I pass grid[1] to a method and the method changes an element, why does the caller see the change, and what does the reference point to?
java
Output
9
Notes on the code
  • grid[1] is an int[] value, so it matches the int[] parameter of fill.
  • Inside fill, row names the same array that grid[1] refers to.
  • The caller prints grid[1][0] and sees 9, because the change was made in the shared row array.

Rows That Need Not Match

Because each row is its own one-dimensional array that the outer array points to, the model does not require every row to have the same length. The source's emphasis on rows as independent arrays is the reason this is possible. The outer array only stores references, so each reference can lead to a row of whatever size that row was created with. Grids whose rows differ in length are called jagged arrays.

java
Output
2 5
Notes on the code
  • new int[2][] creates the outer array with two row slots, leaving each row to be assigned separately.
  • Each row is then created on its own, so the two rows have different lengths.

Mistakes About Rows and Grids

  • Common mistake

    Assuming the whole grid is one rectangular block of storage

    What it looks like

    Picturing int[][] A = new int[3][4] as twelve cells in a single rectangle.

    Why it fails

    The outer array holds three references, and each reference leads to a separate row array.

    Do this instead

    Think of the outer array as a table of contents that points to row arrays, and read A[1][2] as a two-step lookup.

  • Common mistake

    Reading int[][] as a single int[] with an extra bracket

    What it looks like

    Treating int[][] A as if A itself held ints directly.

    Why it fails

    The type int[][] means array of int[], so each element of A is an int[] and not an int.

    Do this instead

    Read the type from the inside out: int, then int[] for a row, then int[][] for the grid.

  • Common mistake

    Expecting a passed row to be copied

    What it looks like

    Calling fill(grid[1]) and expecting grid[1][0] to stay unchanged after fill writes to row[0].

    Why it fails

    A row is a value of type int[], and the method's parameter refers to the same row array.

    Do this instead

    Expect changes made through a passed row to be visible to the caller, and keep this in mind when you pass rows to methods.

  • Common mistake

    Forgetting that a row can have a different length from its neighbors

Practice Tracing a Row Through a Method

MEDIUM

Given int[][] B = new int[2][3]; and a method static void setFirst(int[] r) that sets r[0] to 5, what do the following print? Call setFirst(B[0]); then print B[0][0] and B[1][0]. Explain your answer in terms of which array objects the parameter and the caller refer to.

Hints
  • B[0] is an int[] value, so it can be passed directly to setFirst.
  • The parameter r and B[0] refer to the same row array.
  • B[1] is a different row array, so it is not changed by the call.

Key Takeaways

  • Java has no true two-dimensional arrays; a two-dimensional array is an array whose elements are one-dimensional arrays.
  • The type int[][] means array of int[], so each element of the outer array is a variable of type int[] that refers to one row.
  • The grid picture is a useful model for indexing such as A[1][2], but the real structure is an outer array of references to separate row arrays.
  • Because each row is a value of type int[], a single row can be passed to any method with an int[] parameter, and changes made through that parameter are visible to the caller.
  • Since each row is its own array, rows are not forced to share one length, which is how jagged arrays arise.