I think the key misunderstanding is revealed in:
I think that I declare x
, and then y
refers to x
.
Variables in Java hold references to objects (and primitives, but that's not really important here). The only thing that can be referred to by a variable is an object. Variables are not objects, and thus nothing can refer to them. Let's consider the two code samples more closely.
In the first case, there are two variables and one array:
public static void main(String[] args) {
String[] x = {"A"};
String[] y = x;
x[0] = "B";
System.out.print(x[0] + " " + y[0]);
}
It may help to think in terms of what things are actually values, and what things are just references, or pointers, or handles (various) names, that refer to actual values. x
and y
are both variables and the values of these variables are references to objects (in this case, arrays of strings). The particular value of x
, in this case, is the same as the value of y
, it's a reference to an array with one element, the String "A"
. The expression x[0]
is evaluated by retrieving the array to which the variable x
has a reference and taking its first element. The expression y[0]
is evaluated by retrieving the array to which the variable y
has a reference and taking its first element. Because x
and y
hold references to the same array, the first element of the array is the same as itself. The printed output is B B
.
In the second case, there are two variables and no arrays.
public static void main(String[] args) {
String x = "A";
String y = x;
x = "B";
System.out.print(x + " " + y);
}
The variable x
holds a reference to a string, "A"
. The first assignment, String y = x;
makes y
hold a reference to the same string, "A"
. At this point, if you could modify anything about the string (but you can't in Java, because strings are immutable), you could do it using either x
or y
, and you'd see the result in either, because both variables have a reference to a single object. However, the second assignment x = "B";
makes the value of a x
a reference to a different string, "B"
. It doesn't change the value of y
, which is still a reference to the string "A"
. So, the expression x
is evaluated and since x
holds a reference to the string "B"
, the result is "B"
. The expression y
is evaluated, and since y
holds a reference to the string "A"
, the result is "A"
. The printed output is B A
.
Perhaps the key point is that variables and objects are completely distinct. Objects exist, period. Variables hold references to objects. When you do something like
x.doSomething();
you're retrieving the value of x
, which is an object, and then calling that object's doSomething()
method. You can retrieve the object to which a variable refers, and you can make a variable refer to a different object (through assignment). Those are the only things you can do to an variable. Anything else you can do, you're doing to an object. This is particularly important in cases like:
String[] x = {"A"}; ; there's an array {"Α"} and the variable `x` _refers_ to it
String[] y = x; ; retrieve the array to which `x` refers, and make `y` refer to it, too
x[0] = "B"; ; retrieve the array to which `x` refers (and to which `y` also refers)
; and make "B" its first element.
String x = "A"; ; there's a string "A", and the variable `x` _refers to it
String y = x; ; retrieve the string to which `x` refers, and may `y` refer to it, too
x = "B"; ; make `x` refer to the string "Β" (has no effect on what `y` refers to)