String Pool Experiment
Problem Statement
Write a Java program that demonstrates the Java string pool by comparing string literals, strings created with new String(), and interned strings using both the == operator (for reference equality) and the equals() method (for content equality). The program should analyze the memory usage implications and equality behavior of these strings, explaining how the string pool affects object references. Test the implementation with various cases, including identical literals, constructed strings, and interned strings, to highlight the differences in memory and equality. You can visualize this as exploring a shared library of strings where some books (strings) are reused to save space, while others are new copies, and checking if they’re the same book or just have the same content.
Input: None (the program defines strings for testing).
Output: Results of == and equals() comparisons for different string creation methods, along with an explanation of memory usage and string pool behavior.
Constraints:
- Strings contain printable ASCII characters.
- The program focuses on demonstrating string pool mechanics, not specific input constraints. Example:
- Strings:
s1 = "hello",s2 = "hello",s3 = new String("hello"),s4 = s3.intern(). - Output:
s1 == s2: true (same string pool reference) s1.equals(s2): true (same content) s1 == s3: false (different objects) s1.equals(s3): true (same content) s1 == s4: true (s4 interned to string pool) s1.equals(s4): true (same content) - Memory: Literals (
s1,s2) share a single string pool object;s3creates a new object;s4reuses the pool object.
Pseudocode
FUNCTION demonstrateStringPool()
SET s1 to string literal "hello"
SET s2 to string literal "hello"
SET s3 to new String("hello")
SET s4 to s3.intern()
SET s5 to new String("hello")
SET s6 to string literal "world"
PRINT s1 == s2 and s1.equals(s2)
PRINT s1 == s3 and s1.equals(s3)
PRINT s1 == s4 and s1.equals(s4)
PRINT s3 == s5 and s3.equals(s5)
PRINT s1 == s6 and s1.equals(s6)
PRINT memory usage explanation
ENDFUNCTION
FUNCTION main()
CALL demonstrateStringPool()
ENDFUNCTION
Algorithm Steps
- Create strings using different methods:
a.
s1,s2: String literals (stored in the string pool). b.s3,s5: New String objects (created on the heap, not pooled). c.s4: Interned version ofs3(references the string pool). d.s6: Different string literal for contrast. - Compare strings using:
a.
==to check reference equality (are they the same object?). b.equals()to check content equality (are the characters the same?). - Print comparison results for each pair.
- Explain memory usage:
- String literals share a single object in the string pool.
new String()creates a new object on the heap.intern()returns a reference to the string pool object.
- In the
mainmethod, call the demonstration function and include test cases to show string pool behavior.
Java Implementation
public class StringPoolExperiment {
// Demonstrates string pool behavior with comparisons
public void demonstrateStringPool() {
// String literals
String s1 = "hello";
String s2 = "hello";
// New String object
String s3 = new String("hello");
// Interned string
String s4 = s3.intern();
// Another new String object
String s5 = new String("hello");
// Different string literal
String s6 = "world";
// Empty string literal
String s7 = "";
String s8 = "";
// Comparisons
System.out.println("Test case 1: Literal vs Literal (s1 = \"hello\", s2 = \"hello\")");
System.out.println("s1 == s2: " + (s1 == s2) + " (same string pool reference)");
System.out.println("s1.equals(s2): " + s1.equals(s2) + " (same content)\n");
System.out.println("Test case 2: Literal vs New String (s1 = \"hello\", s3 = new String(\"hello\"))");
System.out.println("s1 == s3: " + (s1 == s3) + " (different objects)");
System.out.println("s1.equals(s3): " + s1.equals(s3) + " (same content)\n");
System.out.println("Test case 3: Literal vs Interned String (s1 = \"hello\", s4 = s3.intern())");
System.out.println("s1 == s4: " + (s1 == s4) + " (same string pool reference)");
System.out.println("s1.equals(s4): " + s1.equals(s4) + " (same content)\n");
System.out.println("Test case 4: New String vs New String (s3 = new String(\"hello\"), s5 = new String(\"hello\"))");
System.out.println("s3 == s5: " + (s3 == s5) + " (different objects)");
System.out.println("s3.equals(s5): " + s3.equals(s5) + " (same content)\n");
System.out.println("Test case 5: Literal vs Different Literal (s1 = \"hello\", s6 = \"world\")");
System.out.println("s1 == s6: " + (s1 == s6) + " (different string pool references)");
System.out.println("s1.equals(s6): " + s1.equals(s6) + " (different content)\n");
System.out.println("Test case 6: Empty Literal vs Empty Literal (s7 = \"\", s8 = \"\")");
System.out.println("s7 == s8: " + (s7 == s8) + " (same string pool reference)");
System.out.println("s7.equals(s8): " + s7.equals(s8) + " (same content)\n");
// Memory usage explanation
System.out.println("Memory Usage Analysis:");
System.out.println("- String literals (s1, s2) share a single object in the string pool, saving memory.");
System.out.println("- s3 and s5 create new objects on the heap, each with separate memory.");
System.out.println("- s4 (interned) reuses the string pool object, reducing memory usage.");
System.out.println("- s6 uses a different string pool object for \"world\".");
System.out.println("- Empty literals (s7, s8) share a single empty string in the pool.");
System.out.println("- Actual memory usage depends on JVM; string pool reduces duplication.");
}
// Main method to run the demonstration
public static void main(String[] args) {
StringPoolExperiment experiment = new StringPoolExperiment();
experiment.demonstrateStringPool();
}
}
Output
Running the main method produces:
Test case 1: Literal vs Literal (s1 = "hello", s2 = "hello")
s1 == s2: true (same string pool reference)
s1.equals(s2): true (same content)
Test case 2: Literal vs New String (s1 = "hello", s3 = new String("hello"))
s1 == s3: false (different objects)
s1.equals(s3): true (same content)
Test case 3: Literal vs Interned String (s1 = "hello", s4 = s3.intern())
s1 == s4: true (same string pool reference)
s1.equals(s4): true (same content)
Test case 4: New String vs New String (s3 = new String("hello"), s5 = new String("hello"))
s3 == s5: false (different objects)
s3.equals(s5): true (same content)
Test case 5: Literal vs Different Literal (s1 = "hello", s6 = "world")
s1 == s6: false (different string pool references)
s1.equals(s6): false (different content)
Test case 6: Empty Literal vs Empty Literal (s7 = "", s8 = "")
s7 == s8: true (same string pool reference)
s7.equals(s8): true (same content)
Memory Usage Analysis:
- String literals (s1, s2) share a single object in the string pool, saving memory.
- s3 and s5 create new objects on the heap, each with separate memory.
- s4 (interned) reuses the string pool object, reducing memory usage.
- s6 uses a different string pool object for "world".
- Empty literals (s7, s8) share a single empty string in the pool.
- Actual memory usage depends on JVM; string pool reduces duplication.
Explanation:
- Test case 1:
s1ands2(literals) reference the same string pool object, so==andequals()are true. - Test case 2:
s3(new String) is a separate heap object, sos1 == s3is false, butequals()is true. - Test case 3:
s4(interned) references the pool object, sos1 == s4is true. - Test case 4:
s3ands5are distinct heap objects, so==is false, butequals()is true. - Test case 5:
s1ands6are different pool objects, so both==andequals()are false. - Test case 6: Empty literals share the same pool object, so both
==andequals()are true.
How It Works
- String Literals: Stored in the string pool, a part of the JVM’s heap where identical literals share a single object (e.g.,
s1,s2point to the same"hello"). - new String(): Creates a new object on the heap, even if the content exists in the pool (e.g.,
s3,s5are separate from"hello"in the pool). - intern(): Returns the string pool reference for the content, reusing the pool object if it exists (e.g.,
s4points to the same"hello"ass1). - == vs equals():
==checks if two references point to the same memory address.equals()checks if the string contents are identical.
- Memory Usage:
- Literals save memory by reusing pool objects.
new String()creates additional heap objects, increasing memory usage.intern()reduces memory by reusing pool objects.
- Example Trace (Test case 1):
s1 = "hello",s2 = "hello": Both reference the same pool object.s1 == s2: true (same reference).s1.equals(s2): true (same content).
- Main Method: Tests various combinations to show string pool behavior and memory implications.
Complexity Analysis Table
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| String Creation | O(1) | O(n) |
| == Comparison | O(1) | O(1) |
| equals() Comparison | O(n) | O(1) |
| intern() | O(n) | O(1) |
| Full Algorithm | O(n) | O(n) |
Note:
- n is the length of the longest string.
- String creation: O(1) for literals (pool lookup), O(n) for
new String()(copying characters). ==: O(1), compares references.equals(): O(n), compares each character.intern(): O(n), may involve hash table lookup and string comparison.- Space: O(n) for each new String object; literals reuse pool space.
- Full algorithm: O(n) time for comparisons and interning; O(n) space for new String objects.
✅ Tip: Use string literals for constant strings to leverage the string pool and save memory. Use
intern()sparingly to reduce memory for dynamically created strings, but test thoroughly to understand its behavior.
⚠ Warning: Avoid using
==to compare string contents, as it checks references, not values. Overusingnew String()can increase memory usage unnecessarily due to duplicate objects.