String s1 = "Java";
String s2 = "Java";
StringBuilder sb1 = new StringBuilder();
sb1.append("Java");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(sb1.toString() == s1);
System.out.println(sb1.toString().equals(s1));
Why is the third print statement printing false? How to make it print true?
1. String Interning
As an result of Strings immutability the JVM can make optimization to store only one copy of each literal String in the Java String Pool (the special memory region where Strings are stored by the JVM). This process is called interning
If found, the Java compiler will simply return a reference to its memory address, without allocating additional memory. If not found, it'll be added to the pool and its reference will be returned.
String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); //true
2. Strings Allocated Using the Constructor
Creating a string using the new
operator will create a new object and store it in the heap space
Every String created like this will point to a different memory region with its own address
String s1 = "Java";
String s2 = new String("Java"); //or
StringBuilder sb1 = new StringBuilder();
sb1.append("Java");
System.out.println(sb1.toString() == s1);; //false
System.out.println(s2 == s1);; //false
3. Conclusion
When we create a String object using the new() operator, it always creates a new object in heap memory. On the other hand, if we create an object using String literal, it may return an existing object from the String pool
4. Manual Interning
Manually interning the String will store its reference in the pool, and the JVM will return this reference when needed
String s1 = "Java";
String s2 = new String("Java").intern(); //or
StringBuilder sb1 = new StringBuilder();
sb1.append("Java");
System.out.println(sb1.toString().intern() == s1);; //true
System.out.println(s2 == s1);; //true