CodeToConcept
About

java

java Tutorials

Introduction
Java Variables
Java Data Types
Java Type Casting
Java Operators
Java Input/Output
Java Class & Object
java Method
Java Constructor
Java this keyword
Java super keyword
Java Method Overloading and Overriding
Java Interface
Java Abstract Class
Java Memory Management
Design Patterns
JDBC (Database Connectivity)
Java IDEs

java Tutorials

Introduction
Java Variables
Java Data Types
Java Type Casting
Java Operators
Java Input/Output
Java Class & Object
java Method
Java Constructor
Java this keyword
Java super keyword
Java Method Overloading and Overriding
Java Interface
Java Abstract Class
Java Memory Management
Design Patterns
JDBC (Database Connectivity)
Java IDEs

Sample Question

Think it through, then check the tutorial.

CodeToConcept

Quickly learn through simple, structured, and practical coding tutorials. Build your confidence from step zero to real-world experience.

© 2026 CodeToConcept. All rights reserved.

Quick Links

AboutTutorials

Tutorials

JavaHTMLCSS

Support

Privacy PolicyTerms of ServiceContact
GitHubTwitterYouTube

String Pool in Java

The String pool gives equal interned text one shared String reference. Literals use this sharing, and intern() can request it for text created at runtime. Content equality and reference identity remain different questions.

Why Does Java Have a String Pool?

Strings are used very frequently in Java applications.

Consider:

String a = "Java";
String b = "Java";
String c = "Java";

If Java created a separate object for every identical literal, it would use unnecessary memory.

Instead, Java can maintain one pooled "Java" instance and allow multiple references to refer to it.

Conceptually:

String Pool
 
        "Java"
       /   |   \
      a    b    c

Example

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

Output

true

Why? Because both String literals can refer to the same pooled String object.

String Pool and String Immutability

String pooling works especially well because Strings are immutable.

Suppose:

String a = "Java";
String b = "Java";

Both references can safely share the same String object.

If Strings were mutable, changing the object through a could unexpectedly change what b sees.

Because Strings cannot be modified, this sharing is safe.

String Literal vs new

Consider:

String a = "Java";
String b = new String("Java");

The literal "Java" can refer to the pooled String.

The new String("Java") expression creates a separate String object.

Therefore:

ExpressionReference behavior
String a = "Java";Refers to the pooled literal
String b = new String("Java");Creates a separate object, so a == b is false
String c = b.intern();Returns the canonical pooled reference, so a == c is true

Use equals() to compare string contents; use == only when reference identity is intended.

System.out.println(a == b);

Output

false

But:

System.out.println(a.equals(b));

Output

true

The contents are equal, but the references are different.

The intern() Method

The String class provides an intern() method.

It returns the canonical representation of the String from the String pool.

Example

String a = "Java";
 
String b = new String("Java");
 
String c = b.intern();
 
System.out.println(a == c);

Output

true

Here, b.intern() returns the pooled "Java" String.

Understanding intern()

Consider:

String a = "Java";
String b = new String("Java");

Conceptually:

String Pool             Heap
 
 "Java"                  "Java"
   ↑                       ↑
   a                       b

After:

String c = b.intern();

c refers to the pooled String:

String Pool             Heap
 
 "Java"                  "Java"
 ↑   ↑                     ↑
 a   c                     b

Therefore, a == c is true.

Compile-Time String Concatenation

Java can combine constant String expressions at compile time.

For example:

String a = "Java";
String b = "Ja" + "va";

The expression can be treated as the same pooled literal value.

Therefore:

System.out.println(a == b);

prints:

true

Runtime String Concatenation

Now consider:

String first = "Ja";
String second = "va";
 
String result = first + second;
 
String literal = "Java";
 
System.out.println(result == literal);

The result of the concatenation is not necessarily the same reference as the pooled literal.

For modern Java, the compiler typically uses StringConcatFactory/invokedynamic for runtime concatenation.

If you want the pooled canonical representation:

String result = (first + second).intern();

Then result == literal can be true.

String Pool and new String()

Consider:

String a = "Hello";
String b = new String("Hello");

The String literal "Hello" is associated with the pool.

The new expression creates another String object.

Therefore:

System.out.println(a == b);

prints:

false

But:

System.out.println(a.equals(b));

prints:

true

Where is the String Pool Located?

In modern JVM implementations, the String pool is associated with the heap, not the old permanent generation.

Older Java versions had different memory arrangements, but since Java 7, interned Strings are stored on the heap.

Therefore, avoid the outdated explanation:

"String pool is stored in PermGen."

For modern Java, that statement is incorrect.

Is Every String Stored in the String Pool?

No.

Consider:

String a = new String("Java");

The String created by new is not automatically the pooled instance.

You can explicitly request the canonical pooled representation:

String b = a.intern();

Why is the String Pool Useful?

1. Reduces duplicate String objects

Equal literals can share a pooled instance.

2. Can reduce memory usage

Repeated literals do not necessarily require separate pooled objects.

3. Supports efficient sharing

Immutable Strings can safely be shared.

4. Enables canonical representation

intern() can be used when an application specifically needs canonical String instances.

Should We Always Use intern()?

No.

intern() should not be used automatically for every String.

Interning has a purpose, but excessive or unnecessary interning can increase memory usage and add overhead.

Use it when canonical String identity is useful for the application and the trade-offs are understood.

For ordinary String comparison, use:

a.equals(b);

rather than relying on:

a == b;

String Pool Example

public class HelloWorld {
 
    public static void main(String[] args) {
 
        String a = "Java";
        String b = "Java";
 
        String c = new String("Java");
        String d = c.intern();
 
        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a == d);
 
        System.out.println(a.equals(c));
    }
}

Output

true
false
true
true

Explanation:

a == b — Both can refer to the same pooled String.

a == c — c refers to a separate object created using new.

a == d — d refers to the canonical pooled String returned by intern().

a.equals(c) — Both contain the same characters.

String Pool vs Heap

A simplified view is:

                   JVM Heap
                       |
            -----------------------
            |                     |
       String Pool          Other Objects
            |
       "Java"
       "Hello"
       "World"

The String pool is part of heap-managed memory in modern JVMs.

This diagram is simplified; the JVM's actual memory management is more complex.

Key Takeaway

The String Pool is a JVM-managed collection of canonical String instances that allows Java to reuse equal String literals and explicitly interned strings. Because String objects are immutable, sharing them is safe and can reduce unnecessary duplicate objects.

Remember

String literal
      ↓
String Pool
      ↓
Can be shared
 
new String(...)
      ↓
New String object
 
intern()

↓ Canonical pooled String

And when comparing String contents: a.equals(b);

is normally the correct choice rather than: a == b;

See you in next page....🙂

← How many ways to create String in JavaOverview →
← How many ways to create String in JavaOverview →