Providing technology solutions that help you reach the world
String Interning in Java

String Interning in Java

Even though Strings may be the most commonly used object in all of Java, how they get created and compared are less known and appreciated. For example, creating a string directly from a literal or explicitly as an object (using new) may give seemingly similar results, but the underlying objects that are created are actually very different. Consider the following token example.

String red1 = "#ff0000";
String red2 = "#ff0000";
String red3 = new String("#ff0000");

Because strings in Java are immutable, those corresponding to the same literal can be shared. The String class maintains a private object pool in the Java heap space. When creating a string directly from a literal, Java first checks if a string of the same literal already exists in the pool. If so, the string from the pool is returned; otherwise, one is created, added to the pool, and returned. However, creating a string object explicitly always returns a new, separate object not in the pool.

In the example above, red1 and red2 are created directly from the same literal, so they share the same object in the string pool. On the other hand, red3 is created explicitly using new, so it is an object outside the pool. In most cases, a developer may not be aware or care about this detail, but it can catch one off-guard when the strings are being compared.

red1 == red2; // true
red1.equals(red2); // true
red1 == red3; // false
red1.equals(red3); // true

If we didn’t know about the Java string pool, we may at first be surprised that red1 == red2 is true, but this is indeed the case because red1 and red2 are actually the same object residing in the string pool. red1 == red3 is false because red3 is a distinctly separate object. Of course, .equals() performs the comparison on the literals themselves, so it returns true in all cases.

With constant literals, we almost always create their string objects directly, but we must resort to explicit object creation if the value is not known at compile time. In the latter case, is there a way to force the string into the pool even though it was created as a separate object? That’s where intern() comes into play. This method creates the string in the pool (if it doesn’t already exist) and returns the pool’s copy, essentially transforming the string’s original explicit creation into a direct literal form.