4

I know that array a and b are pointing to the same place where as Strings s1, s2 are not. Why?

Code:

    String[] a = {"a","b","c"};
    String[] b = a;
    a[0] = "Z";
    String s1 = "hello";
    String s2 = s1;
    s1 = "world";
    System.out.println(Arrays.toString(a) + " - a"); //a and b are same
    System.out.println(Arrays.toString(b) + " - b");
    System.out.println(s1 + " "+ s2); // s1 and s2 are not same.

Output:

    [Z, b, c] - a
    [Z, b, c] - b
    world hello
Charan
  • 1,051
  • 3
  • 12
  • 32

4 Answers4

5

At point (2), s1 and s2 are pointing to the same literal in the pool. But when you change s1, another literal is created and the strings are not pointing to the same place anymore.

String s1 = "hello";
String s2 = s1; (2)
s1 = "world";

You can validate this by printing the result of

s1 == s2

Note that I didn't use equals because I'm interested in comparing references. Now as soon as you assign s1 with a different value, things will look like:

+-------+
| world |  <- s1
+-------+

+-------+
| hello |  <- s2
+-------+
Maroun
  • 94,125
  • 30
  • 188
  • 241
  • Great explanation! So, basically Java sees Strings and arrays differently. Primitives are special. All other objects that we create work similar to the array object. Right? – Charan Sep 16 '15 at 13:29
  • 3
    @Charan No. You just need to know the difference between mutable and immutable objects :) That's all. – Suresh Atta Sep 16 '15 at 13:32
2

Arrays are objects and thus if you change an array element you change the object which both a and b point to.

Strings are immutable objects so you can only change the reference, what you are doing when calling s1 = "world".

A little more in-depth explanation:

Strings:

String s1 = "hello"; //creates a new String object with value "hello" and assigns a reference to that object to s1
String s2 = s1;  //s2 now points to the same object as s1
s1 = "world"; //creates a new String object with value "world" and assigns a reference to that object to s1

So in the end s1 will point to a different string object with the value "world".

Arrays:

String[] a = {"a","b","c"}; //creates the array and assigns a reference to it to variable a
String[] b = a; //copies the reference of a to b, so both point to the same object
 a[0] = "Z"; //changes the 1st element in the array, a and b still point to it

Here you never change the actual value of a which is the reference to the array but you rather change the value of the array's 1st element which is itself a reference to the string "Z".

Thomas
  • 87,414
  • 12
  • 119
  • 157
2

a and b are references to the same Array (there is a single Array object in memory.)

a ---> ["a", "b", "c"] <---- b

You are changing this array value with this line :

a[0] = "Z"

So you know have this in memory :

a ---> ["Z", "b", "c"] <---- b

For the Strings, it's different.

At first, you have two variables pointing the same value :

String s1 = "hello";
String s2 = s1;

You have this in memory :

s1 ---> "hello" <---- s2

But then, you assign s1 to a new value with this code :

s1 = "world";

The variable s2 still points to the string "hello". There are now 2 string objects in memory.

s1 ---> "world" 
s2 ---> "hello"

In Java, Strings are immutable, but arrays are mutable. See also this question.

Note that if you define a class of yours, the behavior will be closer to the Array.

public class Foo() {
  private int _bar = 0;
  public void setBar(int bar) {
    this._bar = bar   
  }
  public void getBar() {
    return this._bar;
  }
}


Foo f1 = new Foo();
Foo f1 = f2;

You have this :

f1 ----> Foo [ _bar = 0 ] <---- f2

You can work on the object :

f1.setBar(1)
f2.setBar(2) // This is the same object

This makes something a bit "like" the array :

f1 ----> Foo [ _bar = 2 ] <---- f2

But if you assign f2 to another value, you get this :

f2 = new Foo();

Which creates a new value in memory, but still keeps the first reference pointing to the first object.

f1 ----> Foo [ _bar = 2 ] 
f2 ----> Foo [ _bar = 0 ]
phtrivier
  • 13,047
  • 6
  • 48
  • 79
  • So, basically Java sees Strings and arrays differently. Primitives are special. All other objects that we create work similar to the array object. Right? – Charan Sep 16 '15 at 13:27
  • 1
    A couple of things are immutable : primitives (int, float, etc...), their wrappers (Integer, Float, etc...) and Strings are among those. In general, classes that you define yourself, and most other classes are mutable. (They will behave more or less like arrays.) – phtrivier Sep 16 '15 at 13:31
1

The key difference is reassignment versus modification.

Reassignment (x = ...) makes the variable point to a new object but doesn't change the underlying object, thus any other variables pointing to the original object will not be changed.

Modification (x.something = ... or x[...] = ...) only changes the underlying object, thus any other variables pointing to the same object will reflect the changes.

Note that Strings are immutable - they have no methods that modify them and no (non-final) public member variables, so they can't be modified (without reflection).


You can think of people pointing at books being your variables and the books themselves being the underlying objects.

Many people can point at the same book. You can have someone point at a different book without changing the book itself or what anyone else is pointing at. If you write something in a book someone's pointing at everyone pointing to that book will see the changes.

int[] a = {0,1,2,3,4}; // Assign a to, let's say, "Object 1"
int[] b = {5,6,7,8};   // Assign b to, let's say, "Object 2"
int[] c = a;           // Assign c to Object 1
a[0] = 2;              // Change Object 1's 0th element
assert c[0] == 2;      // c points to Object 1, whose 0th element is now 2
a = b;                 // Assign a to Object 2
assert c[0] == 2;      // c still points to Object 1
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138