Java String Equality Example

Sorry in advance for the main question, but can someone explain to me why:

String s = "lo";
String str7 = "Hel" + s;
String str8 = "He" + "llo";
System.out.println("str7 == str8 is " + (str7 == str8));

      

outputs false. I thought str7 and str8 both point to the same object in the string pool, because strings are immutable.

Am I wrong? Do str7 and str8 exist not in the pool but on the heap? Why?

Can you provide me with an example of some string manipulation where the result is actually the same immutable string from the string pool?

PS:

String str9 = "He" +"llo";
System.out.println("str8 == str9 is " + (str9 == str8));

      

outputs true

+3


source to share


4 answers


Your understanding is correct in the case of a pool, where all literals end up in the string pool.

And confusion arises when you do concatenation. There are two points to note.

1) If the String is resolved at compile time, yes, it syncs with the String pool and uses the same literals. For ex

String str7 = "Helllo";
String str8 = "He" + "llo";

      

Note that both are simple literals. Hence, there are no runtime conversions etc.

2) If String resolves at runtime, it resolves newline at runtime and differs with any other string, unless you use the .equals method to compare its contents.

String str7 = "Hel" + s;
String str8 = "He" + "llo";
System.out.println("str7 == str8 is " + (str7 == str8)); //false

      

In this case, concat strings with operator (+), the JVM returns new StringBuilder(string...).toString()

because it is a simple literal and the other is a variable.



Look at the Java Language Specification

If only one operand expression is of type String, then a string conversion (ยง5.1.11) is performed on the other operand to create a string at runtime.

Questions from comment:

does this mean that in case a string is created as the product of a concatenation of literals then the result is always the same string in the pool?

Yes it is. Remember, concatenation, which you mean by compile-time expression (as a constant expression), not Runtime.

And when we concatenate a string literal with a string object, then the resulting string is always a new string object created with a StringBuilder under the hood?

Yes, a new line was returned. The attached JVM connection confirms this.

+4


source


String s = "lo";
String str7 = "Hel" + s;
String str8 = "He" + "llo";
String str9 = "He" + "llo";

      

The referenced s

object is a String object that represents the literal "lo". It is in the row pool.

The objects referenced by str8

and str9

are the result of evaluating an expression that is a constant expression. Therefore, they are in the row pool. And in fact, since expressions are evaluated on the "same" string, str8

they str9

refer to the same actual object String

.

The referenced object str7

is the result of evaluating an expression that is NOT a constant expression. Therefore it is NOT in the row pool.

The final reason "Hel" + s

it is not a constant expression is because s

it was not declared as final

.




The thing to remember is that String objects are only allocated in the String pool in two cases:

  • If they are the result of evaluating a constant expression, or
  • If they are explicitly created using the String.intern()

    .

String literals are a constant expression auxiliary case.

For a more detailed explanation of what a constant expression is, see the Java Language Specification - JLS 15.28 (constant expression) and JLS 4.12.4 (constant variable).

Any row that is not created under one of these circumstances is not in the row pool.

+2


source


str7

and str8

are in the pool, but they are not the same string. That is, they are different versions of the same sequence of characters.

Think about the performance you would get if the VM had to scan the entire pool every time a line was created to see if there was another line with the same sequence of characters.

In your new example, you are creating both tags str8

and str9

from the same base strings, so the compiler can more confidently say that the result of each is the same and can reuse that entry in the pool.

+1


source


If you call String#intern()

, the compiler scans the pool String

and executes as you seem to expect. I.e

String s = "lo";
String str7 = ("Hel" + s).intern();
String str8 = ("He" + "llo").intern();
System.out.println("str7 == str8 is " + (str7 == str8));

      

Outputs

str7 == str8 is true

      

There are two reasons for this behavior.

  • String

    is immutable, so use +

    requires creating new String

    (s)
  • String

    concatenation is usually implemented with StringBuilder

    - new StringBuilder("Hel").append(s).toString()

    and new StringBuilder("He").append("llo").toString()

    and StringBuilder

    does not scan the String

    intern pool .
0


source







All Articles