What is the difference between String s = "hi" and String s = new String("hi") in terms of object creation and identity?
answer
- Literal = pooled, shared, one object
- new String() = always a fresh heap object
- == compares identity, equals() compares value
- "hi" == "hi" true; "hi" == new String("hi") false
basics
~20 sA string literal like "hi" is stored in a shared pool, so equal literals point to the same object. new String("hi") always makes a brand-new object on the heap, separate from the pool, even if the text is identical.
solid answer
~40 sA string literal is interned automatically: the compiler/JVM keeps one canonical instance in the string pool, so two identical literals are the same object and compare true with ==. new String("hi") forces allocation of a fresh String on the heap whose char data is distinct from the pooled copy, so literal == new String(...) is false even though equals() is true. The new String constructor is wasteful: it creates an extra object that just duplicates a value already in the pool. That is why "hi" == "hi" is true but "hi" == new String("hi") is false. Always compare strings with equals() for value comparison; reserve == for identity checks. Use literals (or intern) to benefit from sharing; avoid new String() unless you specifically need a distinct instance.
go deeper
Knows literals share one object and new String makes a fresh one; uses equals() not == for comparison.
Explains == identity vs equals() value, why new String wastes memory, and can predict == results in mixed cases.
Discusses the pool's role in memory optimization, when new String is justified (rare), and the link to immutability and security (defensive copies).
Frames pooling as a deduplication strategy, weighs it against GC/footprint and JIT escape analysis, and sets team guidance to ban new String() except for documented cases.
## Background: what a String is In Java, `String` is an immutable object: once created, its character contents never change. Because strings are everywhere and immutable, Java optimizes memory by **sharing** identical string values. ## The string pool (a.k.a. string literal pool / intern pool) The **string pool** is a special table the JVM maintains of canonical `String` instances. For every distinct text value in the pool there is exactly **one** `String` object. It lives in normal heap memory (since Java 7; before that it was in the PermGen area). When you write a **string literal** in source code — e.g. `"hi"` — the compiler records it in the class file's constant pool, and at runtime the JVM ensures the pool contains one canonical `String` for that value. Every place in the program that uses the literal `"hi"` gets a reference to that **same** object. ## Two key operators - `==` compares **references** (identity): are these two variables pointing at the *same object in memory*? - `.equals()` compares **values**: do the two strings contain the *same characters*? ## Case 1: `String s = "hi";` This takes a reference to the pooled object. So: ```java String a = "hi"; String b = "hi"; a == b; // true — same pooled object a.equals(b); // true — same value ``` ## Case 2: `String s = new String("hi");` The `new` keyword **always** allocates a fresh object on the heap. The argument `"hi"` is itself a pooled literal, but `new String(...)` copies its characters into a brand-new, separate `String`. So: ```java String a = "hi"; String c = new String("hi"); a == c; // false — different objects a.equals(c); // true — same value ``` `new String("hi")` is essentially wasteful: it creates **two** string-related entities (the pooled literal plus the new copy) when one would do. ## Why this matters 1. **Correctness:** beginners often compare strings with `==` and get surprising results. For value comparison you must use `.equals()`. The literal-vs-new distinction is the classic trap that exposes this bug. 2. **Memory:** literals are shared; `new String` duplicates. In tight loops or large data sets, accidental `new String` allocations waste heap. ## Summary table | Expression | Where the object lives | `== "hi"`? | |---|---|---| | `"hi"` | string pool (shared) | true | | `new String("hi")` | fresh heap object | false | **Rule of thumb:** use literals; use `.equals()` for comparison; only use `new String()` when you deliberately need a distinct instance.
- How do you make new String("hi") == "hi" return true?Call .intern() on it: new String("hi").intern() == "hi" is true, because intern() returns the canonical pooled reference.
- Are the characters inside new String("hi") shared with the pool?No. The new String gets its own copy of the character data, distinct from the pooled literal.
saying these in an interview costs you the question
- Claiming new String("hi") returns the pooled object
- Saying == works for string value comparison
- Thinking literals are also created fresh each time
- Confusing immutability with pooling — they are related but distinct ideas