"==" in case of string concatenation in Java

String a = "devender"; String b = "devender"; String c = "dev"; String d = "dev" + "ender"; String e = c + "ender"; System.out.println(a == b); //case 1: o/p true System.out.println(a == d); //case 2: o/p true System.out.println(a == e); //case 3: o/p false 

a and b both point to the same string literal in the string constant pool. So true in case 1

 String d = "dev" + "ender"; 

something like - should be used internally

 String d = new StringBuilder().append("dev").append("ender").toString(); 

How do a and d point to the same link, not a and e ?

+50
java string
Dec 29 '15 at 10:58
source share
7 answers

Four things go on:

  • (You know that for sure, but for lurkers) == checks if the variables point to the same String object , and not to equivalent strings. Therefore, even if x is equal to "foo" , and y also "foo" , x == y can be true or false, depending on whether the tags x and y belong to the same String object or to different ones. Therefore, for string comparisons for equivalence we use equals , not == . All of the following is explained by why == sometimes true, it is not a suggestion to use == to compare strings. :-)

  • Equivalent string constants (strings that the compiler knows are constants according to different rules in JLS) in the same class, refer to the same string by the compiler (which also lists them in the "constant pool" class). That is why a == b true.

  • When a class is loaded, each of its string constants is automatically interned - the JVM string pool is checked for the equivalent string, and if it is found, the String object is used (if not, a new String object for the new constant is added to the pool). Therefore, even if x is a string constant initialized in the Foo class, and y is a string constant initialized in the Bar class, they will be == each other.

    Points 2 and 3 above are partially described by JLS§3.10.5 . (The bit about the pool of class constants is a little detail of the implementation, so the link to the JVM specification earlier, JLS just talks about interning.)

  • The compiler performs string concatenation if it deals with constant values, therefore

     String d = "dev" + "ender"; 

    compiled into

     String d = "devender"; 

    and "devender" is the string constant that the compiler and JVM apply to points 2 and 3 above. For example, no StringBuilder used, concatenation occurs at compile time, and not at run time. This is described in JLS§15.28 - Constant Expressions . Thus, a == d true for the same reason a == b is true: they refer to the same constant string, so the compiler guaranteed that they refer to the same string in the pool of class constants.

    The compiler cannot do this if any of the operands is not a constant, so it cannot do this with

     String e = c + "ender"; 

    ... although code analysis can easily show that the value of c will certainly be "dev" , and thus e will definitely be "devender" . The specification contains only a constant concatenation compiler. Therefore, since the compiler cannot do this, it issues the StringBuilder code that you referenced, and this work is done at run time, creating a new String object. This line is not executed automatically, therefore e ends with a reference to a different String object than a , and therefore a == e is false.

    Note that as Vinod said , if you declared c as final :

     final String c = "dev"; 

    Then it will be a constant variable (yes, they are really called), and therefore §15.28 is applicable, and the compiler will enable

     String e = c + "ender"; 

    at

     String e = "devender"; 

    and a == e also true.

Just to repeat: none of this means that we should use == to compare strings for equivalence. :-) What equals for.

+79
Dec 29 '15 at 11:04
source share

The compiler does a lot of optimization under the hood.

 String d = "dev" + "ender"; 

Here, the compiler will replace "dev" + "ender" with "devender" when compiling the program. If you add 2 literals (this applies to both primitives and strings), the compiler does this optimization.

Java Code:

 String d = "dev" + "ender"; 

Bytecode:

  0: ldc #16 // String devender 

Transition to a special case:

 final String c = "dev"; // mark this as final String e = c + "ender"; 

Creating c final will make String a compile-time constant. The compiler will understand that the value of c cannot change and, therefore, will replace all events of c the value "dev" during compilation, thus e will be allowed during compilation itself.

+16
Dec 29 '15 at 11:05
source share

As you said internally, the last concatenation is done with something similar to

 String e = new StringBuilder().append(c).append("ender").toString(); 

the implementation of toString() StringBuilder creates a new line . Here is the implementation.

 public String toString() { // Create a copy, don't share the array return new String(value, 0, count); } 

Comparing strings using == instead of .equals() returns true only if both strings are the same . In this case, they do not match, since the second string is created as a new object of type String .

Other concatenations are performed directly by the compiler, so no new String is created.

+9
Dec 29 '15 at 11:04
source share

"dev" + "ender" is a constant expression for evaluating compilation time: both arguments are string literals. Hence the expression "devender" .

The same cannot be said for c + "ender" : some circumstances (for example, some code running in another thread) may cause the value of c be set to a different value. Qualifying c as final eliminates this possibility, in which case e also refers to the same object as a .

So a , b and d all refer to the same object.

+9
Dec 29 '15 at 11:04
source share

The difference between d and e is that when string literals are concatenated, concatenation is performed at compile time. The Java compiler treats the expression "dev" + "ender" in the same way as the expression "devender" , creating the same literal at compile time. Since all String literals get interned, d , which is the result of "dev" + "ender" , also ends with a reference to the same object as a and b "devender" .

The expression for e , which is c + "ender" , is evaluated at runtime. Despite the fact that it creates the same line, this fact is not used by the compiler. Therefore, another String object arises, which leads to an unsuccessful comparison with == .

+9
Dec 29 '15 at 11:04
source share

String d = "dev" + "ender"; constant + constant, d is always a constant (one and the same), therefore (a == d) is true;

String e = c + "ender"; variable + constant, the result of 'e' is a variable, it will use StringBuilder inside and create a new link.

+6
Dec 29 '15 at 11:21
source share

Keep in mind that Java contains a pool of all the string literals found in the program, used to match targets among others, so any literal string linked above will lead to the same object, in addition to the string literal. You can check out this helpful article for more details.

On the other hand, concatenating a String object and a literal (case c + "ender" ) will create an as StringBuilder at runtime other than the literals found in the pool.

0
Dec 30 '15 at 11:52
source share



All Articles