What does the String.intern() method do, and how does it interact with the string pool?
answer
- intern() = canonical pooled reference
- Found in pool -> return it; not found -> add then return
- a.intern()==b.intern() iff a.equals(b)
- Bridges runtime strings into the literal pool
- Costs a hash lookup; can bloat the pool
basics
~20 sintern() looks in the shared string pool for a string with the same value. If one is there, it returns that pooled object; if not, it adds the current string to the pool and returns it. The result is a canonical reference equal-valued strings can share.
solid answer
~50 sString.intern() returns a canonical representation of the string from the pool. When you call s.intern(), the JVM checks whether the pool already holds a string equal (by value) to s. If yes, it returns the existing pooled reference; if no, it adds s (or an equivalent) to the pool and returns that. The guarantee is: for any two strings a and b, a.intern() == b.intern() exactly when a.equals(b). This lets runtime-built strings (from concatenation, parsing, I/O) be deduplicated so they share one instance and can be compared with ==. Literals are interned automatically, so "x".intern() == "x". The classic use is reducing memory when many duplicate strings arrive at runtime, or enabling fast == comparison after canonicalization. Caveats: interning has a hash-lookup cost, the pool is a GC root concern historically, and over-interning can hurt rather than help.
go deeper
Knows intern() returns a shared pooled copy and that literals are already interned.
States the iff contract (a.intern()==b.intern() iff a.equals(b)) and explains finding vs adding to the pool.
Weighs intern() cost vs benefit, knows the pool moved to heap in Java 7, and identifies good (low-cardinality dedup) vs bad (high-cardinality) use cases.
Decides interning policy at scale, considers alternatives (custom canonicalizing maps, G1 string dedup), and reasons about GC/pool-size impact across services.
## What problem intern() solves String **literals** in source code are automatically placed in the **string pool** — a JVM-managed table holding one canonical `String` per distinct value. But strings created at **runtime** — by concatenation, `StringBuilder`, parsing numbers, reading files or network data — are ordinary heap objects and are **not** in the pool, even if their value already exists there. `intern()` is the method that lets you *manually* connect a runtime string to the pool. ## Exact behavior When you call `s.intern()`: 1. The JVM searches the pool for a string whose value `.equals(s)`. 2. **If found:** it returns the reference to that already-pooled string. 3. **If not found:** it adds `s` (the canonical instance) to the pool and returns it. The formal contract from the JavaDoc: > For any two strings `a` and `b`, `a.intern() == b.intern()` is `true` **if and only if** `a.equals(b)` is `true`. So after interning, **value equality becomes reference equality**. This is the whole point: you can replace expensive `.equals()` comparisons with cheap `==` once all candidates are interned. ## Example ```java String a = "hello"; // pooled literal String b = new String("hello"); // fresh heap object String c = ("hel" + "lo"); // compile-time constant -> pooled String d = ("hel" + new String("lo")); // runtime concat -> NOT pooled a == b; // false a == b.intern(); // true — intern() returns the pooled 'a' a == c; // true — constant folding pooled it a == d; // false a == d.intern(); // true — interning canonicalizes d ``` ## How the pool is stored Internally the pool is a hash table keyed by string value. `intern()` therefore costs a hash computation plus a lookup/insert. Since Java 7 the pool lives in the **regular heap** (not PermGen), so interned strings can be garbage-collected once nothing references them and the pool entry is reclaimable. ## When to use intern() - **Memory deduplication:** if you parse millions of records with a small set of repeated values (e.g. country codes, enum-like tokens), interning collapses duplicates to single instances. - **Fast comparison:** after canonicalizing, `==` replaces `equals()` in hot paths. ## When NOT to use it / pitfalls - **Lookup cost:** every `intern()` call does a pool hash-lookup; in a tight loop this can be slower than just using `equals()`. - **Pool growth:** interning arbitrary, high-cardinality strings bloats the pool and can hurt GC. - **Subtle bugs:** relying on `==` for strings is fragile — one un-interned path breaks it. Prefer `equals()` unless you fully control interning. ## Summary `intern()` = "give me the one canonical pooled copy of this value, creating it if needed." It bridges runtime strings into the literal pool, trading a lookup cost for sharing and `==` comparability.
- Does string concatenation at runtime produce a pooled string?No. Only compile-time constant expressions are folded and pooled. Runtime concatenation (involving a variable or new String) yields a fresh, un-pooled object; call intern() to pool it.
- What is the time cost of intern()?It performs a hash-table lookup in the pool (and an insert on miss), so it is not free. In hot loops it can be slower than a direct equals() comparison.
saying these in an interview costs you the question
- Saying intern() mutates the string in place
- Claiming intern() is always a memory win regardless of cardinality
- Thinking runtime concatenation results are auto-pooled
- Believing intern() guarantees == for non-equal strings