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.