JavaStrings

Strings

Text is everywhere in programming, and in Java it is represented by the String class. Strings look and feel like a primitive — Java gives them special syntax support — but under the hood they are full objects with some unusual and important behaviors.
Strings Are Objects With Special Support
Technically, String is a reference type — it is a class defined in java.lang, not one of the eight primitives. However, Java grants it two conveniences that ordinary classes don't get: you can create one with a plain string literal, and you can combine strings with the + operator.

String literals and concatenation

Java
public class StringBasicsDemo {
    public static void main(String[] args) {
        String first = "Hello"; // string literal — no 'new' required
        String second = "World";

        String greeting = first + ", " + second + "!"; // + concatenation

        System.out.println(greeting);
    }
}
Hello, World!
Strings Are Immutable
This is the foundational fact about Strings in Java: once a String object is created, its contents can never be changed. Every method that appears to modify a string — .toUpperCase(), .trim(), .replace(), even + concatenation — actually leaves the original string untouched and returns a brand new String object with the result.

The original string never changes

Java
public class ImmutabilityDemo {
    public static void main(String[] args) {
        String original = "hello";
        String upper = original.toUpperCase();

        System.out.println(original); // still "hello"
        System.out.println(upper);    // a brand new String, "HELLO"
    }
}
hello
HELLO
Warning
Calling original.toUpperCase() does not change original. It creates and returns a completely new String object. If you don't capture the return value (e.g. by writing just original.toUpperCase(); on its own line and ignoring the result), the uppercase version is discarded and effectively lost. This is one of the most common mistakes beginners make with Strings.
The String Pool and Literal Interning

Because Strings are immutable, Java can safely share identical string literals between different parts of a program. When you write a string literal, Java checks a special memory region called the string pool: if an identical literal already exists there, the new variable reuses that same object instead of creating a new one.

Literals share the same pooled object

Java
public class StringPoolDemo {
    public static void main(String[] args) {
        String a = "hello";
        String b = "hello";
        System.out.println(a == b); // true — same pooled object

        String c = new String("hello");
        System.out.println(a == c); // false — a new, separate object
    }
}
true
false
Note
a and b are both literals with the same text, so they are "interned" and point at the exact same object in the string pool — making a == b true. c, on the other hand, is created with new String("hello"), which explicitly forces the creation of a fresh, separate object on the heap, even though its text content is identical. This is a classic Java gotcha that trips people up because the values look identical when printed.
Always Use .equals() to Compare Content
The example above demonstrates exactly why you should never rely on == to compare String content. == checks whether two references point at the same object — a reference comparison. To check whether two strings contain the same characters — a value comparison — use .equals().

Broken vs. correct comparison

Java
public class StringComparisonDemo {
    public static void main(String[] args) {
        String input = new String("yes");
        String expected = "yes";

        // Broken: compares references, not content
        if (input == expected) {
            System.out.println("Match (== )");
        } else {
            System.out.println("No match (==)");
        }

        // Correct: compares actual character content
        if (input.equals(expected)) {
            System.out.println("Match (.equals())");
        }
    }
}
No match (==)
Match (.equals())
Warning
Even though input and expected both hold the text "yes", input == expected is false because new String(...) guarantees a distinct object. This kind of bug is especially dangerous because it often works by accident in quick tests (when both values happen to come from literals) and then fails mysteriously in production once a string arrives from user input, a file, or a network call.
Tip
Rule of thumb: for Strings (and any object type), use .equals() to compare values and reserve == for checking whether two references point at the literal same object — which is rarely what you actually want to ask.