15

I am really confused with how string interning works in Java. When I write:

String a = "ABC";
String b = "ABC";

if (a==b)
    System.out.println("Equal");

Does the compiler store the string literal "ABC" into the string constant pool at compile time?

That sounds illogical, because I thought the string constant pool was created by the JVM at runtime, and I don't see how that is possible if it is done at compile time since the Java compiler does not even invoke the JVM.

If it is not done at compile time and it is done at runtime then why does the following return false (taken from this answer)?

// But .substring() is invoked at runtime, generating distinct objects
"test" == "!test".substring(1) // --> false

If it is done at runtime then why can't the JVM figure out that they are the same string?

I am really confused as to how string interning works in Java and where exactly the Java string pool is stored.

4
  • The following link is insightful: stackoverflow.com/questions/513832/… Commented Apr 26, 2015 at 14:59
  • I'm not sure about the first part of your question, but substring returns a new object, and so while the content of both strings match to test, since they are not the same object == returns false. Commented Apr 26, 2015 at 14:59
  • 2
    It's the compiler. I don't understand why you say that it cannot both put the strings in the string constant pool. The compiler will put the constant strings inside some memory location, then when launching the program the JVM will load that memory and create the constant pool to be used at runtime, but the pool is setup by the compiler. Commented Apr 26, 2015 at 14:59
  • How is this not a duplicate more than 6 years after Stack Overflow was launched? Commented Apr 26, 2015 at 15:52

2 Answers 2

20

The compiler puts the literal strings in the class file (and only unique ones, it consolidates all equivalent literals); the JVM loads those strings into the string pool when the class file is loaded.

If it is done at runtime then why can't the JVM figure out that they are the same String.

Because the string being returned by .substring has not been interned, and so is a different object than the equivalent "test" string in the string pool. If you interned it, you'd get true:

"test" == "!test".substring(1).intern() // true

Sections §4.4 of the JLS and §5.3 of the JVM spec look relevant.


Just to be clear: The correct way to compare strings in Java is to use the .equals method or similar, not ==. Using == with string instances is usually incorrect. (Unless you're playing with understanding when and how things are interned...)

Sign up to request clarification or add additional context in comments.

12 Comments

The documentation for substring @ docs.oracle.com/javase/7/docs/api/java/lang/… specifically states it returns a new string object.
Just adding some detail. Nice answer.
@T.J.Crowder so intern() avoids new Object right ?
@RobertBain: intern isn't free, it comes with a cost. The caller may not A) Want the performance overhead, and/or B) Not want the string returned to be in the pool. I certainly don't want to look things up in a table every time I create a substring, nor put every single transient substring I create put in the pool.
@Kramer786: The pool stores references to strings, which are normal objects stored in the usual way. The purpose of the pool is purely to avoid having multiple copies of equivalent strings, it doesn't put them elsewhere in memory. Re how it finds them, implementation details are just that and thus can vary from JVM to JVM, but it probably uses a B-tree or hashing mechanism or similar.
|
0

I checked .class for

String a = "ABC";
String b = "ABC";

and found only one "ABC" in it. That is javac creates one constant of the same string at compile time.

But if 2 or more classes have the same "ABC" constant then JVM will place them at the same location in string pool

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.