Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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; s3 creates a new object; s4 reuses 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

  1. 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 of s3 (references the string pool). d. s6: Different string literal for contrast.
  2. Compare strings using: a. == to check reference equality (are they the same object?). b. equals() to check content equality (are the characters the same?).
  3. Print comparison results for each pair.
  4. 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.
  5. In the main method, 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: s1 and s2 (literals) reference the same string pool object, so == and equals() are true.
  • Test case 2: s3 (new String) is a separate heap object, so s1 == s3 is false, but equals() is true.
  • Test case 3: s4 (interned) references the pool object, so s1 == s4 is true.
  • Test case 4: s3 and s5 are distinct heap objects, so == is false, but equals() is true.
  • Test case 5: s1 and s6 are different pool objects, so both == and equals() are false.
  • Test case 6: Empty literals share the same pool object, so both == and equals() 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, s2 point to the same "hello").
  • new String(): Creates a new object on the heap, even if the content exists in the pool (e.g., s3, s5 are separate from "hello" in the pool).
  • intern(): Returns the string pool reference for the content, reusing the pool object if it exists (e.g., s4 points to the same "hello" as s1).
  • == 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

OperationTime ComplexitySpace Complexity
String CreationO(1)O(n)
== ComparisonO(1)O(1)
equals() ComparisonO(n)O(1)
intern()O(n)O(1)
Full AlgorithmO(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. Overusing new String() can increase memory usage unnecessarily due to duplicate objects.