Back to String & String Pool
Q3Question 3 of 12

What is String interning and how does it affect == comparisons?

Key Concepts
  • intern() returns the canonical pooled version of the String
  • If the pool already has an equal String, it returns that existing reference
  • After interning, == comparison works because both references point to the same pooled object
  • Literals are auto-interned; new String() is not
  • Do not rely on == for Strings – always use .equals()

Definition

intern() adds a String to the pool and returns the pooled reference. After interning, == works because both references point to the same object. But always use .equals() in practice.

Interning:

  • intern() checks the pool. If an equal String exists, returns it. If not, adds the current String and returns it.
  • Literals are auto-interned. "hello" is always pooled.
  • new String() is NOT interned. You must call .intern() manually.
  • After interning, == works. But do not rely on this in production code.

The bank's master directory. When you ask the directory to register an account number, it checks if it already exists. If yes, it gives you the existing card (same reference). If no, it registers yours. Now anyone who asks for that number gets the same card.

Understanding the Concepts

How interning works

JAVA
String a = "SAV2001";              // auto-interned (literal)
String b = new String("SAV2001");  // NOT interned (heap object)
String c = b.intern();             // returns the pooled version

System.out.println(a == b);  // false (different objects)
System.out.println(a == c);  // true  (both point to pool)

When is intern() useful?

Rarely in modern Java. It can save memory when processing files with many repeated strings:

JAVA
// Reading 1 million CSV rows with repeated account types
String type = csvFields[2].intern();  // if "SAVINGS" already pooled, reuse it

But String.intern() uses a native hash table with contention under load. Consider -XX:+UseStringDeduplication with G1 GC as a better alternative.

What should a senior engineer know?

  • Do not intern unique strings. Interning transaction IDs fills the pool with entries that never match.
  • Pool is a hash table. Tune with -XX:StringTableSize.
  • G1 String deduplication is automatic and avoids the manual intern() overhead.

What are common mistakes?

A frequent mistake is using == to compare String content instead of equals().

Wrong approach:

JAVA
package com.bank.service;

public class AccountValidator {
    public boolean validateAccountType(String type) {
        // WRONG: == compares references, not content
        if (type == "SAVINGS") {
            return true;
        }
        return false;
    }
}

Correct approach:

JAVA
package com.bank.service;

public class AccountValidator {
    public boolean validateAccountType(String type) {
        // CORRECT: equals() compares content
        if ("SAVINGS".equals(type)) {  // null-safe: literal first
            return true;
        }
        return false;
    }
}

Using the literal on the left side of equals() prevents NullPointerException when the variable is null. This is a standard practice at National Bank of India for all string comparisons in service code.

What are the edge cases?

String behavior has several surprising edge cases that can catch banking developers off guard.

JAVA
package com.bank.edge;

public class StringEdgeCases {
    public static void main(String[] args) {
        // Edge case 1: compile-time constant folding
        String a = "SAV" + "2001";       // Compile-time constant
        String b = "SAV2001";
        System.out.println(a == b);       // true (same pool entry)

        // Edge case 2: variable concatenation is NOT pooled
        String prefix = "SAV";
        String c = prefix + "2001";       // Runtime concatenation
        System.out.println(b == c);       // false (different objects)

        // Edge case 3: final variable IS a compile-time constant
        final String finalPrefix = "SAV";
        String d = finalPrefix + "2001";  // Compile-time constant
        System.out.println(b == d);       // true (same pool entry)

        // Edge case 4: substring no longer shares char array (Java 7u6+)
        String full = "AccountNumber:SAV2001";
        String sub = full.substring(14); // New String, new char array
    }
}
TEXT
true
false
true

The final keyword makes the variable a compile-time constant, which changes how the compiler handles concatenation.

What are common interview follow-up questions?

Interviewers often follow up with these related questions:

  • How does this concept apply to a high-throughput banking transaction system?
  • What are the performance implications in a production environment?
  • How would you debug issues related to this concept?
  • What tools would you use to monitor this in production?
  • How does this behave differently in Java 8 vs Java 17+?

When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.

Visual Overview

DIAGRAM
  "SAV2001"             → auto-interned (literal)
  new String("SAV2001") → NOT interned (heap)
  .intern()             → returns pooled reference

  a = literal, b = new, c = b.intern()
  a == b: false    a == c: true    a.equals(b): true

Key Takeaway

intern() returns the canonical pooled version of a String. Literals are auto-interned. After interning, == works because both references point to the same pooled object. But always use .equals() in production code.

One sentence to remember: intern() returns the pooled reference – literals are auto-interned, new String() is not.

---

Share
Use ← → arrow keys to navigate