Skip to main content

Command Palette

Search for a command to run...

Java String Pool Explained: Why == Sometimes Lies

Updated
5 min readView as Markdown
Java String Pool Explained: Why == Sometimes Lies

Java String Pool Explained: Why == Sometimes Lies

Quick Guides is a series of short, practical explanations of core software engineering concepts. Each guide focuses on one topic, explains how it works, why it exists, and the common pitfalls every developer should know.

Java String Pool Explained

If you've ever seen this in Java:

String a = "hello";
String b = "hello";
System.out.println(a == b); // true

...and then this:

String c = new String("hello");
System.out.println(a == c); // false

you've already encountered the String Pool.

Understanding how it works can help you write more efficient code and avoid one of Java's most common interview questions.

What problem does the String Pool solve?

Strings are everywhere.

"GET"
"POST"
"ERROR"
"SUCCESS"
"userId"

Applications often create the same string values thousands—or even millions—of times.

Without any optimisation:

"hello"
"hello"
"hello"
"hello"

would create four separate objects in memory, all containing identical data.

That's wasteful.

Instead, Java keeps a shared cache of string literals called the String Pool.

How it works

Whenever Java encounters a string literal:

String s = "hello";

it first checks the String Pool.

String Pool
+-------------+
| "hello" || "world" || "GET" |
+-------------+

If "hello" already exists, Java simply returns a reference to the existing object.

If it doesn't exist, Java creates it once and stores it in the pool.

Every future occurrence of "hello" reuses that same object.

We'll trace one running example — variables a, b, c, and d — through the rest of this guide, so each new concept builds on the one before it.

Example: two literals, one object

String a = "hello";
String b = "hello";
System.out.println(a == b);

Memory looks like this:

String Pool
+-----------+
|  "hello"  |
+-----------+
   ^     ^
   |     |
   a     b

Both variables point to the exact same object.

Output:

true

Using new String()

Now bring in a third variable, building on the same a and b above:

String c = new String("hello");

This call explicitly creates a brand-new object on the heap, bypassing the pool entirely.

String Pool                    Heap
+-----------+              +-----------+
|  "hello"  |              |  "hello"  |
+-----------+              +-----------+
   ^     ^                       ^
   |     |                       |
   a     b                       c
System.out.println(a == c);

Output:

false

Even though the text is identical, c points to a different object than a and b.

== vs .equals()

This is where many developers get caught.

== compares object references.

a == b   // true  — both point at the pooled object
a == c   // false — c is a separate object on the heap

asks:

Are these the exact same object?

.equals() compares the contents.

a.equals(c)

asks:

Do these strings contain the same characters?

Output:

true

As a rule:

Use == only if you intentionally want to compare references.

Use .equals() to compare string values.

What does intern() do?

Java also provides:

String d = c.intern();

intern() checks whether an identical string already exists in the String Pool.

If it does, it returns the pooled instance.

Otherwise, it adds the string to the pool and returns that pooled reference.

Since "hello" is already in the pool — thanks to a — calling c.intern() doesn't create anything new. It just hands back the pooled reference:

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

Output:

true
false

d now points at the same pooled object as a and b. c still refers to its own separate object on the heap — intern() doesn't change c itself, it only returns a different reference.

Why this improves performance

Pooling provides several benefits:

Less memory usage

Fewer duplicate objects

Reduced garbage collection pressure

Faster reference comparisons when appropriate

Imagine parsing an HTTP server.

Without pooling:

GET
GET
GET
GET
POST
POST

might create millions of identical string objects.

With pooling:

Pool
GET
POST
PUT
DELETE

Only one copy of each literal needs to exist.

Common interview question

What does this print?

String a = "Java";
String b = "Ja" + "va";
String c = new String("Java");
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a.equals(c));

Answer:

true
false
true

Why?

"Ja" + "va" is a compile-time constant, so Java places "Java" in the String Pool.

new String() always creates a new object.

.equals() compares the characters rather than the object reference.

When should you care?

Most of the time, you don't need to think about the String Pool—Java manages it automatically.

However, it's useful to understand when:

debugging unexpected == comparisons

optimising memory usage in high-throughput applications

analysing heap dumps

preparing for Java interviews

working on performance-sensitive systems

Key takeaways

Java stores string literals in the String Pool.

Identical literals share the same object.

new String() always creates a new object.

== compares references.

.equals() compares string contents.

intern() returns the pooled version of a string.

The String Pool reduces memory usage and improves performance by avoiding duplicate string objects.

Final thoughts

The String Pool is one of Java's oldest and most effective optimisations. It's largely invisible during day-to-day development, but understanding it explains why two strings that look identical can behave differently when compared.

Whenever you're comparing strings, remember:

Compare values with .equals(), not references with ==.

That one habit will save you from countless subtle bugs.

Quick Guides

Part 2 of 2

**Quick Guides** is a series of concise, practical articles that explain core software engineering, cloud, networking, distributed systems, and infrastructure concepts in just a few minutes. Each guide focuses on one topic, cutting through the jargon with clear explanations, simple and interactive diagrams, real-world examples, and interview-ready takeaways.

Start from the beginning

NAT Explained in 5 Minutes: The Internet's Address Translator

NAT Explained in 5 Minutes: The Internet's Address Translator TL;DR Network Address Translation (NAT) allows devices using private IP addresses to communicate with the public Internet by translating