Difference Between Creating String via Literal and via new
There are two ways to create a string in Java, and they work differently:
π’ Junior Level
There are two ways to create a string in Java, and they work differently:
Via literal (recommended):
String s = "Hello";
JVM checks the String Pool. If such a string already exists β returns a reference to it. If not β creates a new one in the pool.
Via constructor new (not recommended):
String s = new String("Hello");
Always creates a new object in regular heap, ignoring the String Pool for the object itself.
Example:
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); // true (same object in pool)
System.out.println(s1 == s3); // false (s3 β separate object)
System.out.println(s1.equals(s3)); // true (content is the same)
When to use: In 99% of cases, use literals. The new String(...) constructor is mainly needed when converting from byte[]/char[], and also in rare cases for creating a guaranteed independent copy (defensive copying).
π‘ Middle Level
How it works internally
Literal:
String s = "Hello";
- Bytecode:
LDCinstruction (Load Constant) - JVM checks String Pool by string hash
- If found β returns reference, if not β creates object in pool
- Optimization happens at class loading stage
Constructor:
String s = new String("Hello");
- Bytecode:
NEWβDUPβLDC "Hello"βINVOKESPECIAL - The literal
"Hello"is already in String Pool new String(...)creates a second object in Regular Heap with the same content- Result: two objects in memory with identical text
Typical mistakes
-
Mistake:
new String("literal")for βguaranteed uniquenessβ Solution: This is an antipattern. String object uniqueness is almost never needed -
Mistake: Thinking
new String()is faster Solution: Literals are faster β they use the pool and donβt create extra objects
When the constructor is actually needed
| Case | Example | Explanation |
| βββββββ- | βββββββββ | βββββββββ |
| From byte[] | new String(bytes, UTF_8) | Main approach for I/O |
| From char[] | new String(chars) | Character conversion |
| From StringBuffer/Builder | builder.toString() | Implicit constructor call |
π΄ Senior Level
Internal Implementation
Literal bytecode:
0: ldc #2 // String Hello
2: astore_1
One instruction β loading constant from class Constant Pool.
Constructor bytecode:
0: new #3 // class java/lang/String // NEW β allocates memory for new String object
3: dup // DUP β duplicates reference for constructor
4: ldc #2 // String Hello // LDC β loads literal from Constant Pool
6: invokespecial #4 // Method ..."<init>":... // INVOKESPECIAL β calls String constructor
9: astore_1
Four instructions: memory allocation, reference duplication, constant loading, constructor call.
Architectural Trade-offs
Why the constructor exists:
- Historically: for creating strings from raw data (byte[], char[], int[] code points)
- Practically:
new String(String original)copies content into a new array (in Java 7+), guaranteeing independence from the original
Why an independent copy might be needed:
- Before Java 7u6:
substring()shared the parentβschar[].new String(substring)copied the data, freeing the parent array for GC - In modern Java this is irrelevant β
substring()always copies data
Edge Cases
- String with intern():
String s = new String("Hello").intern();Creates an object in Heap, then
intern()checks the pool. If"Hello"is already in pool β returns pool reference, and the Heap object becomes garbage. - Constant Folding:
String s = "Hel" + "lo"; // Compiler folds this into "Hello" at compile timeResult will be in String Pool, as if you wrote
"Hello". - Runtime concatenation:
String a = "Hel"; String s = a + "lo"; // NOT in pool! Created via invokedynamic/StringBuilder
Performance
| Operation | Allocations | Time | GC pressure |
| βββββββ | ββββββββ- | βββββββ | ββββ- |
| "Hello" | 0 (if in pool) | ~0 | None |
| new String("Hello") | 1 object + literal in pool| ~10-20ns | Medium |
| "Hello".intern() | 0 | Hash table lookup | Low |
Production Experience
In JSON/XML parsers, where the same field ("name", "id", "type") appears millions of times:
- Without pool: millions of String objects β significant GC overhead
- With pool: dozens of unique strings β 90%+ memory savings on strings
Monitoring
# See number of String objects
jmap -histo:live <pid> | grep java.lang.String
# Analysis via JOL
System.out.println(GraphLayout.parseInstance(s1).toFootprint());
System.out.println(GraphLayout.parseInstance(s2).toFootprint());
Best Practices
- Never use
new String("literal")without a justified reason - To move a string from Heap to Pool, use
.intern() - If you need a guaranteed independent copy β
new String(existingString)(though this is rarely required)
π― Interview Cheat Sheet
Must know:
- Literal
String s = "Hello"β JVM checks String Pool, returns reference from pool or creates in pool new String("Hello")β always creates a NEW object in heap (even if literal is already in pool)- Literal uses
LDCbytecode, constructor βNEW+DUP+LDC+INVOKESPECIAL - Constant folding:
"Hel" + "lo"is folded by compiler into"Hello"at compile time - Runtime concatenation (
a + "lo") β NOT in pool, created viainvokedynamic/StringBuilder new String("...")creates 2 objects: literal in pool + object in Heap
Frequent follow-up questions:
- How many objects does
new String("Hello")create? β One or two. The literal"Hello"is already in pool (on class load),new String()creates a second object in Heap. - Why does
new String(String)constructor even exist? β For creating an independent copy (defensive copying). Before Java 7u6 this was needed to free memory from shared array. - Which is faster: literal or
new String()? β Literal is faster β 0 allocations (if already in pool).new String()β ~10-20ns + GC pressure. - When is
new String()from byte[]/char[] needed? β This is the main approach for I/O:new String(bytes, UTF_8),new String(chars).
Red flags (DONβT say):
- β β
new String("literal")creates a unique stringβ β creates a duplicate, not uniqueness - β βLiteral and
new String()β the same thingβ β different memory placement - β β
new String()is faster than literalβ β opposite, literal is faster - β βConstant folding works for variablesβ β only for
static finalconstants and literals
Related topics:
- [[1. How String Pool Works]]
- [[3. When to Use intern()]]
- [[9. Can You Use == to Compare Strings]]
- [[7. What Happens When Concatenating Strings with + Operator]]