Strings: Fundamentals & Creation

String basics and creation methods

1. Introduction to Strings

Strings are one of the most frequently used data types in Java programming. Understanding their behavior, methods, and performance characteristics is crucial for writing efficient applications.

Key String Characteristics

  • Immutable: String objects cannot be modified after creation
  • Reference Type: Strings are objects, not primitive types
  • String Pool: Java maintains a pool of string literals for memory efficiency
  • Unicode Support: Strings support Unicode characters (UTF-16)
  • Thread-Safe: String immutability makes them inherently thread-safe

Basic String Declaration

// Simple string declaration
String greeting = "Hello, World!";
String language = "Java";

// Strings are objects with methods
int length = greeting.length();        // 13
String upper = greeting.toUpperCase(); // "HELLO, WORLD!"

System.out.println(greeting); // Hello, World!

2. String Creation Methods

Java provides several ways to create strings, each with different memory and performance implications.

String Literal Creation

String Literals (Recommended)

// String literals - most common and efficient
String name = "Alice";
String city = "New York";
String empty = "";

// Literals support escape sequences
String newline = "First line\nSecond line";
String tab = "Column1\tColumn2";
String quote = "He said \"Hello\"";

// Unicode support
String unicode = "Cafe";
String emoji = "Java rocks!";

Constructor-Based Creation

String Constructors

// Using new keyword (creates new object)
String str1 = new String("Hello");
String str2 = new String();  // Empty string

// From character array
char[] chars = {'J', 'a', 'v', 'a'};
String fromChars = new String(chars);  // "Java"

// From character array subset
String subset = new String(chars, 1, 2);  // "av"

// From byte array
byte[] bytes = {72, 101, 108, 108, 111}; // ASCII for "Hello"
String fromBytes = new String(bytes);  // "Hello"

Constructor vs Literal

Recommendation: Use string literals unless you specifically need a new object. String literals are more memory-efficient and leverage the string pool.

3. String Immutability

One of the most important concepts in Java strings is immutability. Once a String object is created, it cannot be modified.

Immutability Demonstration

String original = "Hello";
String reference = original;

System.out.println("Before: original = " + original);      // Hello
System.out.println("Before: reference = " + reference);  // Hello

// "Modifying" actually creates a new String object
original = original + " World";

System.out.println("After: original = " + original);       // Hello World
System.out.println("After: reference = " + reference);   // Hello (unchanged!)

// They now point to different objects
System.out.println(original == reference);  // false

Why Immutability Exists

Benefits of Immutability

  • Thread Safety: Multiple threads can safely access the same string
  • Security: Prevents accidental or malicious modification
  • Caching: Enables string pooling and hash code caching
  • Simplicity: No need to worry about defensive copying

Immutability in Action

// Each operation creates a new string
String str = "Java";
str.toUpperCase();  // Creates "JAVA" but doesn't change str
str.concat(" Programming");  // Creates "Java Programming" but doesn't change str

System.out.println(str);  // Still "Java"

// To actually change the reference, assign the result
str = str.toUpperCase();  // Now str points to "JAVA"
str = str.concat(" ROCKS");  // Now str points to "JAVA ROCKS"

System.out.println(str);  // "JAVA ROCKS"

Performance Impact

String concatenation in loops creates many temporary objects. For multiple string modifications, use StringBuilder (covered in Part 2).

4. String Pool vs Heap Memory

Java uses a special memory area called the “string pool” to store string literals efficiently.

String Pool Behavior

// String literals go to the string pool
String s1 = "Java";
String s2 = "Java";

// Both point to the same object in the pool
System.out.println(s1 == s2);        // true (same reference)
System.out.println(s1.equals(s2));   // true (same content)

// new String() creates object in heap memory
String s3 = new String("Java");

// Different memory locations
System.out.println(s1 == s3);        // false (different references)
System.out.println(s1.equals(s3));   // true (same content)

The intern() Method

Using intern() Method

String pooled = "Hello";
String heapString = new String("Hello");

System.out.println(pooled == heapString);  // false

// intern() moves string to pool (or returns existing)
String internedString = heapString.intern();

System.out.println(pooled == internedString);  // true

// Practical example with concatenation
String dynamic = new String("Ja") + new String("va");
String literal = "Java";

System.out.println(dynamic == literal);         // false
System.out.println(dynamic.intern() == literal); // true

String Pool

  • String literals
  • Shared references
  • Memory efficient

Heap Memory

  • new String()
  • Separate objects
  • More memory usage

Memory Comparison Example

// Memory-efficient: Uses string pool
String[] countries1 = {"USA", "UK", "USA", "Canada", "UK"};

// Memory-wasteful: Creates separate objects
String[] countries2 = {
    new String("USA"),
    new String("UK"),
    new String("USA"),
    new String("Canada"),
    new String("UK")
};

// Check memory sharing
System.out.println(countries1[0] == countries1[2]);  // true (shared)
System.out.println(countries2[0] == countries2[2]);  // false (separate objects)

Part 1A Summary

In Part 1A, we’ve covered the fundamental concepts of Java strings that form the foundation for all string operations.

Key Takeaways

  • String Immutability: Strings cannot be modified; operations create new objects
  • String Pool: Literals are stored efficiently in a special memory area
  • Memory Efficiency: Use string literals instead of constructors when possible
  • Reference vs Content: Understand the difference between == and equals()