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()