Home > front end >  How does string literal concatenation work in Java?
How does string literal concatenation work in Java?

Time:11-05

If we are concatenating two string literals in Java, then how and where does the new String get created?

class StringClass {
    public static void main(String[] args) {

        String a = "java";
        String b = "ja";
        String c = "va";
        String d = b   c;

        System.out.println(a == d);
    }

}

If both a and d are part of the string pool, then why a == d return false?

Is d not a part of the string pool?

CodePudding user response:

Since b c is not a constant expression it is evaluated at runtime. A string pool entry is not created there.

"Is d not a part of string pool?"

CORRECT. The value of d has not been added to the string pool. Only strings resulting from a constant expression are added to the string pool automatically.

A constant expression is defined in JLS 15.29. I will not reproduce it here in its entirety, but I encourage you to take the time to read it. Intuitively, a constant expression is one that can be evaluated at compile time, but it is a bit more complicated than that.

The reason that b c is NOT a constant expression (here) is that b and c were not declared as final.


Having said all of the above, there is really no need to understand the details of the string pool and when something will be added to it. All you really need to do is follow this "rule":

Do not use == to test if String values are equal. Use the String.equals(Object) method. Always.

Also, do not use String.intern() directly. In recent versions of Java, GC's are able to automatically de-dup any long-lived String objects*. If you are using intern() so that you can use ==,

  1. it is a micro-optimization that could well not be worth it (since interning and the string pool itself incur runtime overheads), and

  2. it is risky ... since you have to be sure that you intern all of the String objects you are going to test ... to avoid incorrect results, and

  3. it makes your code more complicated and harder to reason about.


* Actually, the GC only dedups the strings' respective internal backing arrays. The affected strings are still distinct, so == still doesn't work. The deduping (currently) just saves space ... modulo some 2nd order performance issues.

CodePudding user response:

If we are concatenating two String literals in Java

That's not what your code is doing though. It's concatenating two non-constant variables:

String b = "ja";
String c = "va";
String d = b   c;

If I understand correctly, the compiler "sees" that concatenation, and notes that the operands aren't constant - so it leaves the concatenation to execution time.

If you change those variables to be constant variables by using the final modifier, the compiler notes that both operands of the string concatenation are constant expressions, and then your code prints true:

String a = "java";

// These are now constant variables
final String b = "ja";
final String c = "va";

// Concatenation of constant expressions
String d = b   c;

// This now prints true
System.out.println(a == d);

CodePudding user response:

The reason why a == d returns false has to do with how the operator and the String concatenation works in Java.

When you are concatenating two String objects b and c using the operator, Java creates a new String object to hold the concatenated result. Even though the value of d is same as a, the resulting String object d is a different object in memory.This is because Java creates a new String object for the result of the concatenation, and it doesn't reuse the original String objects.

When you use == to compare them, it checks for reference equality, and since a and d refer to different objects, the comparison returns false.

If you want to compare the contents of a and d, you should use the .equals() method, which checks for string equality based on their content:

System.out.println(a.equals(d));

CodePudding user response:

When you concatenate two string literals:

String d = b   c;

a new String is created at runtime in the heap memory, not in the String pool. The String pool is a special area in the heap memory where JVM stores all the String literals.

If both b and c were final, then compiler would be allowed to put result of b c into a String pool at compile time (final means you will not modify variable at runtime.) Then b c would have the same reference as a variable, and a == d would return true.

If you compare two Strings using == operator, it checks whether they refer to the same object in memory, not their values. In your code a and d are not the same object in memory, so a == d returns false. d is not part of String pool unless you use intern() method on it, for example: String d = (b c).intern();, if String b c already exists in string pool, then its reference will be returned, otherwise a new reference will be stored in string pool and also returned.

CodePudding user response:

"... If both a and d are part of the string pool, then why a == d return false? ..."

A great question.

Firstly, if you use the String#intern method, it will return true.

String d = (b   c).intern();

The JavaDoc for intern states the following.

... All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java Language Specification. ...

And, section 15.29 defines, "Constant Expressions".

A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following: ...

...

So, you'll need to define b and c as, "constant variables".

4.12.4. final Variables.

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.29). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1), reachability (§14.22), and definite assignment (§16.1.1).

Thus, making b and c both final, will cause the values to be "interned".

String a = "java";
final String b = "ja";
final String c = "va";
String d = b   c;
System.out.println(a == d);

Output

true

CodePudding user response:

Memory Storage

Actually Java creates new String object and stores string literals in String constant pool.

For a statement:

String a = "java";

Java Compiler treat it as:

String a = new String("java");

It creates new object/instance of String and set reference to the variable "a" (let say 0x01).

It stores the object in heap, while string literals in the string constant pool.


Concatenation

For the statement:

String d = b   c;

Java will treat like:

String d = new String("ja"   "va");
// equivalent to
String d = new String("java");

Equality Check

As literal "java" already exists in string constant pool, no new entry will be made but new object will be created in heap with some other address (let say 0x02).

Now for the code:

System.out.println(a == d);

Java will check (try to match) the addresses of both variables like that (assumption)

// It will print false as both addresses are different
System.out.println(0x01 == 0x02);

How to Get True

To get true, use

// It will print true
System.out.println(a.equals(d));

.equals(...) will match string literals instead of reference addresses.

  • Related