0

If pool memory already has an object with similar content, then if we try to create the same object with different reference variable then only a new reference variable is created, NO NEW OBJECT IS CREATED.eg;

String s7="1";
String s8 ="1";
System.out.print(s7==s8);  //True

Here only one object is created. But in the following example

public class JavaApplication1 {
    public static void main(String[] args) {
        String s1 = "1", s2 = "2", s4 = s1 + s2, s5 = "12";
        final String s3 = s1 + s2;
        s1 += s2;
        System.out.print((s1 == s3) + "" + (s1 == s5) + "" + "" (s3 == s5));
    }
}

Output is false false false Even is s3 is declared as an final expression!, why?

  • 2
    Because `s1` and `s2` aren't? And what does any of this have to do with "increment"? – chrylis -cautiouslyoptimistic- Nov 14 '17 at 17:36
  • += like in s1+=s2; – Krishnan Mishra Nov 14 '17 at 17:44
  • AFAIK, the compiler only interns the obvious cases - direct string constants and concatenation thereof. Anything else is processed at run time. –  Nov 14 '17 at 17:47
  • But i think final entities are evaluated at compile time only so at least (s3==s5) should be true – Krishnan Mishra Nov 14 '17 at 17:49
  • 1
    @Krishnan no: compile-time constants are final, but final values aren't always compile-time constants. Consider `final String s = "" + System.currentTimeMillis();`: there is no way that can be evaluated at compile time. – Andy Turner Nov 14 '17 at 17:54
  • 1
    Related: [Comparing strings with == which are declared final in Java](https://stackoverflow.com/q/19418427) – Pshemo Nov 14 '17 at 17:57
  • It could be possible to have different results if compiler would be smarter and realize that at time of execution `s1 + s2` there can't be any other values under `s1` or `s2` than "s1" and "s2". But since `s1` and `s2` are not declared as final, compiler assumes that values may vary so it doesn't try to treat them as compilation constants. – Pshemo Nov 14 '17 at 18:02
  • @Pshemo That would be a breach of the JLS actually, as the docs on String concatenation via `+` directly specify that a new object will be created. – Ordous Nov 14 '17 at 18:09
  • @Ordous Yes, for non-compilation-constants new String object will be created at runtime, but in other cases like `"ab"+"cd"` (or if `s1` and `s2` would be final variables containing string literals) compiler will change it to `"abcd"` and will treat it as String literal. In other words it will try to use equal string from string pool, or will add it to string pool if it didn't contain such string. – Pshemo Nov 14 '17 at 18:15
  • @Pshemo I'm aware how interning works. What I meant was that even if the compiler was smart enough to know that the `s1` and `s2` can only have 1 single value at that point in the execution (and I'm pretty sure it already knows this in the case of OPs program), then it still wouldn't be legal to auto-intern the result of their concatenation as per the JLS. It's not (only) a problem of the compiler recognizing that they are effectively constants, it's also a problem of the JLS explicitly saying you can't auto-intern unless they are constants *as defined by the JLS*. – Ordous Nov 14 '17 at 18:19

2 Answers2

3

This is because

1) Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.

2) Strings computed by concatenation at run time are newly created and therefore distinct.

Here's an example:

    String s7 = "77";
    String s8 = "77";

    String s10 = "7";
    String s11 = "7";

    String s9 = s10+s11;
    String s12 = "7"+"7";

    //printing the address
    System.out.println(System.identityHashCode(s7));
    System.out.println(System.identityHashCode(s8));
    System.out.println(System.identityHashCode(s9));
    System.out.println(System.identityHashCode(s12));

    System.out.println(s7==s9);
    System.out.println(s7==s12);

Output:

705927765
705927765
366712642  ---> address is different
705927765
false
true

Although I also went through about this just now. But here's my assumption:

All the literals except String s9 = s10+s11; are computed at compile time. That's why we are getting different address.

Follow the String literals javadoc for more details.

Shubhendu Pramanik
  • 2,711
  • 2
  • 13
  • 23
1

If pool memory already has an object with similar content, then if we try to create the same object with different reference variable then only a new reference variable is created, NO NEW OBJECT IS CREATED.eg;

That is actually not true in the general case. What you are describing is called String interning. An interned String will always be reference-equal to any other interned String with the same content - that's basically the guarantee of intern. (From the docs on String.intern: It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.). If I were to create 2 Strings from a constant byte array, then even as they share the content, those will be different objects.

The JLS further specifies that:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.

Hence why you get equality of String literals, and anything that is a value of [a] constant expression.

So, what is this constant expression? Well, again, according to the JLS, those are literals, Simple names (§6.5.6.1) that refer to constant variables, various non-String stuffs, and expressions with +, but only as long as both operands of + are themselves constant expressions (The String object is newly created (§12.5) unless the expression is a constant expression (§15.28).). So this means that, unless your Strings on both sides of + are literals, final strings with the value being a constant expression or fulfill one of the other conditions (like a cast from a primitive constant), a new object will be created.

Ordous
  • 3,844
  • 15
  • 25