4

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?

Haggra
  • 3,539
  • 2
  • 20
  • 28
  • because string constants are stored in the string table, whereas there is no such thing as "array table" – gefei Nov 16 '15 at 10:38
  • The Strings only refer to the same string because they get interned after the compilation. This is just some sort of optimization which you shouldn´t rely on. Since Strings are still objects it´s neccessary to compare them by using equal. – SomeJavaGuy Nov 16 '15 at 10:38
  • Maybe of interest: https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.6 – Tunaki Nov 16 '15 at 10:39
  • @KevinEsche: No, you can *absolutely* rely on compile-time string constants being interned. It's guaranteed by the specification. Yes, you should do so with care, but it's not like it's an implementation detail. – Jon Skeet Nov 16 '15 at 10:46

4 Answers4

8

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
Natix
  • 14,017
  • 7
  • 54
  • 69
  • *Immutability* of Strings can be broken using Reflection. But yes, you can't make arrays immutable :) – TheLostMind Nov 16 '15 at 10:40
  • 1
    @VinodMadyalkar: And if you do that, Java does in fact break down in places. That's why Reflection requires permissions from a security manager. – Thilo Nov 16 '15 at 10:42
  • 1
    That really makes sense. You cannot change a string so it is safe to use the same object whereas arrays are changed so it is not really safe, thus different objects on the heap are created. And your previous example taught me something new. – Haggra Nov 16 '15 at 10:42
  • 1
    Also note that the exact same thing (re-used internalized instances) happens with some other immutables like `Integer` and `Long` as well. – Thilo Nov 16 '15 at 10:43
  • @Thilo - Yes. Reflection could cause problems. But changing value of `value[]` inside String doesn't look really dangerous. Is it? – TheLostMind Nov 16 '15 at 10:46
  • http://stackoverflow.com/questions/15274874/how-does-java-string-being-immutable-increase-security http://stackoverflow.com/questions/20945049/is-a-java-string-really-immutable – Thilo Nov 16 '15 at 10:48
  • @Thilo - Will check that out. Thanks :) – TheLostMind Nov 16 '15 at 10:48
4

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.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Only Strings are automatically interned or are there any other classes? – Haggra Nov 16 '15 at 10:57
  • 1
    @Haggra: Good question! `Integer` does something similar to interning in that [`Integer.valueOf(int)`](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf-int-) will reuse instances for at least the values -128 to 127 inclusive, and "may" reuse others. This is possible because `Integer` is also immutable. I can't immediately think of other examples, but I'd be surprised if there weren't some. – T.J. Crowder Nov 16 '15 at 11:01
3

System.out.println(s1 == s2); returns true only because we have a String constants pool that checks for Such literals (or interned Strings) and reuses the same Strings. Arrays were never designed for this.

Actually :

String s1 = new String("Some string");
String s2 = new String("Some string");

will give false for System.out.println(s1 == s2);.

TheLostMind
  • 35,966
  • 12
  • 68
  • 104
1

Strings in java are saved in a string table. When you create two of the exact same strings they will reference the same object. If you want to know if the value of a string is the same as another you will have to do String.Equals().

As Arrays are not saved in a array table they will reference different objects. of you want to know if the content of two arrays are the same you will have to itterate through the arrays with String.Equals().

StijnvanGaal
  • 441
  • 3
  • 17
  • "When you create two of the exact same strings they will reference the same object" Not really. That only happens in certain circumstances. You cannot rely on it (unless you call `intern()` ) – Thilo Nov 16 '15 at 10:46
  • True. But as he said his if statement returned true. so that is what was happening. And doing Intern() is pretty expensive isn't it? – StijnvanGaal Nov 16 '15 at 10:50