2

Yesterday I asked the a question about reference by value, strange сopy values ​​from one array to another, and thought that I understood the answer after seeing this code:

public static void main(String[] args) {
  String[] x = {"A"};
  String[] y = x;
  x[0] = "B";
  System.out.print(x[0] + " " + y[0]);
}

Then I saw this example which is identical to the first:

public static void main(String[] args) {
  String x = "A";
  String y = x;
  x = "B";
  System.out.print(x + " " + y);
}

And I do not understand why, in this example, the correct answer will be B A, instead of B B. I think, that I declare x, and then y refers to x.

Community
  • 1
  • 1
Drylozav
  • 183
  • 1
  • 9

6 Answers6

4

First example:

You have declared a String array whose only member is "A". You declare another String array and assign it x. Now you have two array references referring to the same array. You change the contents to be "B", so it's visible to both array references. You modified the contents of the only array object present.

Second example:

You have declared a String whose contents is "A". You declare another String and assign it x. Now you have two string references referring to the same String. You change the variable x to be "B", and now x and y are referring to different strings, so you see "B A". You didn't change the original string object (Strings are immutable).

rgettman
  • 176,041
  • 30
  • 275
  • 357
1

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)
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
1

String objects are immutable, this is why you are getting this behavior.

In your second example, you assign "A" to the variable x, then create variable y, which points to the same String in memory as varaible x. You then change your variable x to point to a new String. However, this doesn't affect the variable y; it still points to the initial String.

Laf
  • 7,965
  • 4
  • 37
  • 52
1

In your second instance, you are setting a String to a value, which is treated as a primitive type in Java. You are doing a one-time value assignment that stays permanent.

In the first instance, when you assign y to x, you are dealing with arrays. Arrays are references to several values in memory, so when you say y = x, you are setting y so that it references the same values as x. Thus, x and y are permanently equal to each other.

By this, x[0] and y[0] are pointing to the same exact value, and if you change one it is changed in both references.

Alex
  • 1,100
  • 1
  • 9
  • 23
1

In your first example, the line

String[] y = x; 

sets x to y. but x refers to a memory address.

so when when you call

x[0] = "B";

you're changing the value at that address, which both x and y refer to.


In the second example, x and y aren't reference types.

so when you call

String y = x;

it takes the value at x and copies it to y, just like in the first example, but since x and y are values instead of addresses, than they're separate.

so when you call

x = "B"

It doesn't affect the value of y at all. y remains "A"

*Technically Strings are references too, it's just that they're immutable, and therefore behave similarly to value types like int and float.

1

In

String[] x = {"A"};

you are creating reference x and assigning it to newly created array

x  ---> ["A"]

Next in

String[] y = x;

you are creating reference y and assigning it with value of x so it will be reference to same array that holds x

x  \
    }--->["A"]
y  /

NOT something like

y -> x ---> ["A"]

Now you have access to the same array via two references. It means that if you modify it via x you will be able to see this modifications via y because it is the same array, so

x[0] = "B";

will do

x  \
    }--->["B"]
y  /

and this is why result of System.out.print(x[0] + " " + y[0]); is B B


Now in your second example

String x = "A";

creates reference x and assigns it string "A"

String y = x;

creates another reference y and assigns it with same value of x so again they will use same object

x  \
    }---> "A"
y  /

but in

x = "B";

are are not modifying same object like in your first example, but changing reference x to hold different String "B" so now situation looks like

x  ---> "B"

y  ---> "A"

which is why System.out.print(x + " " + y); prints B A.

Pshemo
  • 122,468
  • 25
  • 185
  • 269