Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't arrays reference to the same object as strings does?

String reference to the same object if you declare them without the use of "new" keyword as follows:

String s1 = "Some string";
String s2 = "Some string";

System.out.println(s1 == s2); 
//prints true because 
//they reference to the same object

However, contrary to what I expected doing this with array doesn't work:

char[] anArray = {'A', 'r', 'r', 'a', 'y'};
char[] oneArray = {'A', 'r', 'r', 'a', 'y'};
System.out.println("anArray == oneArray : " + (anArray == oneArray));
//prints false

We haven't explicitly mentioned that they are "new" arrays so why doesn't they reference to the same object on the heap?

like image 786
Haggra Avatar asked Dec 05 '22 01:12

Haggra


2 Answers

Because arrays, unlike strings, are mutable. You usually don't want to change an object referenced from one variable through a supposedly independent object referenced by another variable.

char[] firstArray = {'A', 'r', 'r', 'a', 'y'};
char[] secondArray = {'A', 'r', 'r', 'a', 'y'};

firstArray[0] = 'X';
firstArray[1] = '-';

System.out.println(firstArray);
System.out.println(secondArray);

What would the output be if arrays were "interned" (i.e. if same literals pointed to same instances):

X-ray
X-ray

What actually happens: each literal creates a new instance:

X-ray
Array
like image 133
Natix Avatar answered Dec 06 '22 19:12

Natix


We haven't explicitly mentioned that they are "new" arrays so why doesn't they reference to the same object on the heap?

The real question here is: Why would they? It would be a real pain if, in the general case, equivalent objects were conflated by the JVM. Many classes have mutable instances; it's a bit of a problem if you have mutable instances (and arrays are mutable) and the JVM combines them into a single instance without your asking it to.

So by extension, the real question is: Why do your s1 and s2 refer to the same object?

The answer is: Because strings are a special case that the JDK and JVM have special handling for. Strings in Java were designed to be shared where possible, to save on memory size and churn, and so:

  1. They're immutable (although you can break that via reflection if you try hard enough), and so sharing instances is acceptable (since you're not going to change them, officially).

  2. Strings have the ability to be interned, putting them in the JVM-managed string pool.

  3. String literals are automatically interned.

Your s1 and s2 wouldn't refer to the same string if it weren't for #3. Example (live copy):

String s1 = "Some string";
int a = 1;
String s2 = (a == 1 ? "Some" : "Foo") + " string";
System.out.println("Same? " + (s1 == s2));
System.out.println("Equivalent? " + s1.equals(s2));

Output:

Same? false
Equivalent? true

The string generated by the expression and assigned to s2 can't be automatically interned, so it ends up referring to a diffrent string object.

If you had a class with immutable instances, you could implement intern for them as well. Strings are only special in that it's done for us by the Java specification and runtime.

like image 21
T.J. Crowder Avatar answered Dec 06 '22 20:12

T.J. Crowder