An array is a reference
The assignment int b = a puts a copy of the number into b, and from then on each variable lives on its own. Let's do the same with an array and see what happens:
public class Main {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 9;
System.out.println(b[0]); // 9
System.out.println(a[0]); // 9
}
}Let's go line by line:
int[] a = {1, 2, 3};creates an array of three elements.int[] b = a;declares the variableband puts the value ofainto it.b[0] = 9;changes the first element throughb.System.out.println(b[0])prints9, as expected.System.out.println(a[0])prints9too, even though we wrote nothing toa.
To see where the nine came from, let's go back to the row of lockers. The row itself stands in the changing room. The variable a holds not the row but a ticket with its address: the ticket leads you to the right row.
The line int[] b = a made a copy of the ticket. Now there are two tickets but still one row. So whatever is put into a locker using ticket b, the holder of ticket a sees too.
The variable holds a reference
When the program runs {1, 2, 3} or new int[3], the JVM creates the array itself in a separate area of memory, the heap. The variable a gets not the array but a reference: a value by which the JVM finds the array on the heap. That is the ticket. Everything the JVM creates on the heap is called an object, which is why the widget below labels the arrays "object 1" and "object 2".
The rule for = has not changed: assignment copies the value of a variable. The difference is that the value of an int[] is a reference, so int[] b = a copies the reference, not the elements. Now a and b lead to one array.
Types whose variables hold references are called reference types. The array is the first such type we look at closely. The eight primitive types have no references: an int variable holds the number itself. So an element of an int[] is an ordinary int, and int x = a[1]; copies the number: writing x = 7 does not touch the array.
In the widget the first three lines are the same as in the program above, and the fourth creates an array c with the same numbers that a now holds. Run the lines one at a time and watch which object each variable leads to. After the last line the widget offers three comparisons: before you press one, try to guess the answer.
1int[] a = {1, 2, 3};2int[] b = a;3b[0] = 9;4int[] c = {9, 2, 3};
The program has not started yet. Press the button to run the first line.
Here the ticket picture is off. A real ticket exists as a single copy and cannot be duplicated, while Java copies a reference as many times as you like. And you never see the address on the ticket: Java does not show a program where on the heap an array lives.
An array as a method parameter
A reference is copied when you call a method too. A parameter gets a copy of the argument's value, and the value of an array is a reference. So the method and the caller hold tickets to the same row. Say the method's parameter is called nums:
nums[0] = 0;changes an element of that very array, and the caller will see that zero;nums = new int[3];rewrites only the method's copy of the ticket, and the caller's variable still leads to the old array.
In an interview this is put as: Java always passes arguments by value, and for an array the value is a reference.
How to compare two arrays
The whole program from the widget prints three comparisons:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 9;
int[] c = {9, 2, 3};
System.out.println(a == b); // true
System.out.println(a == c); // false
System.out.println(Arrays.equals(a, c)); // true
}
}== compares references
The == operator compares the values of two variables. For int those are numbers, and for arrays they are references. So for arrays == answers the question "is this the same array?":
a == bgivestrue:bholds a copy of the same ticket;a == cgivesfalse:chas its own array, even though its elements are the same.
Arrays.equals compares elements
Arrays.equals(a, c) compares the lengths of the arrays and their elements in order. Here the lengths are equal and the elements 9, 2, 3 match, so the result is true. Order matters: {1, 2} and {2, 1} are different arrays to it.
Interviewers like to ask this: how is == different from comparing contents? For arrays the answer is: == compares references, and Arrays.equals compares the length and the elements.
A real copy
When you need a second, independent array with the same elements, you create it with the method Arrays.copyOf:
int[] src = {1, 2, 3};
int[] copy = Arrays.copyOf(src, src.length);
copy[0] = 9;
System.out.println(Arrays.toString(src)); // [1, 2, 3]
System.out.println(Arrays.toString(copy)); // [9, 2, 3]
int[] longer = Arrays.copyOf(src, 5);
System.out.println(Arrays.toString(longer)); // [1, 2, 3, 0, 0]Arrays.copyOf sets up a new row of lockers and copies the elements into it. The second argument is the length of the new array:
- With the length
src.lengthyou get an exact copy. Writing tocopydoes not touchsrc. - With a length greater than the original, the extra cells are filled with zeros: this is how an array is "made longer".
- With a length less than the original, the copy is cut short:
Arrays.copyOf(src, 2)gives[1, 2].
Common mistake
You wanted a sorted copy and to keep the original order:
int[] scores = {30, 10, 20};
int[] sorted = scores; // ✗
Arrays.sort(sorted);
System.out.println(Arrays.toString(scores)); // [10, 20, 30]The line sorted = scores copied only the reference, and Arrays.sort sorted the one and only array. The original order 30, 10, 20 is lost. You need a real copy: int[] sorted = Arrays.copyOf(scores, scores.length);.
Key points
- An array variable holds a reference to the array on the heap, not the elements themselves.
int[] b = acopies the reference:aandblead to one array, and a write throughbshows througha.==compares references, andArrays.equalscompares the length and the elements in order.- An independent copy is created by
Arrays.copyOf(a, a.length).