Strings are Objects
Java gives strings special syntax, but they are still objects. Learn how literals, references, immutability, equality, and concatenation fit together.
Strings get special treatment in Java. You can use String without writing an import, create one with a literal, and join strings with +. That convenience can make strings look like primitive values. They are not: a string is an object.
A class with convenient syntax
int count = 5;
String message = "Hello";
int is a primitive type. String is a class, and message holds a reference to a String object. The literal "Hello" gives you a string without an explicit constructor call.
String belongs to java.lang, whose public types Java imports automatically. This also explains why you can use System and Object without imports. It is not a privilege reserved for strings.
String message = "Hello";
System.out.println(message.length()); // 5
System.out.println(message.substring(1)); // ello
Object value = message;
You can call methods on a string and assign its reference to an Object variable. The short syntax does not change what it is.
A literal does not mean a fresh object
String first = "Hello";
String second = "Hello";
String third = new String("Hello");
System.out.println(first == second); // true
System.out.println(first == third); // false
System.out.println(first.equals(third)); // true
Java shares identical string literals through interning, commonly described as the string pool. Here, first and second refer to the same object. The explicit constructor creates a distinct String object with the same content.
This makes == a misleading test for text. It checks whether references identify the same object, while equals() checks string content. Prefer literals over unnecessary new String(...) calls, and use equals() when you mean “the same text.” This is the distinction discussed in Identity and Equality.
The language specification also guarantees interning for string-valued constant expressions. For example, "Hel" + "lo" shares the literal "Hello". Do not generalize that guarantee to strings assembled at runtime.
Immutable object, reassignable variable
String message = "Hello";
String original = message;
message = message.concat("!");
System.out.println(message); // Hello!
System.out.println(original); // Hello
A String object is immutable: its content cannot change after creation. In this example, concatenation produces a different string, and the assignment makes message refer to that result. The object referenced by original stays unchanged.
String methods do not edit the receiver in place. Ignoring a returned value therefore does not update your variable:
String message = "Hello";
message.replace("H", "J");
System.out.println(message); // Hello
message = message.replace("H", "J");
System.out.println(message); // Jello
Immutability is a property of the object; final restricts reassignment of a variable. A final String reference cannot be reassigned, but the String object was already immutable. See the String API documentation for its methods and guarantees.
The plus sign has two jobs
System.out.println(1 + 2 + " apples"); // 3 apples
System.out.println("apples: " + 1 + 2); // apples: 12
System.out.println("apples: " + (1 + 2)); // apples: 3
Java gives + special support for string concatenation. These expressions group from left to right. In the first line, two numbers are added before the string is encountered. In the second, the first operation already produces a string, so the next number is appended too. Parentheses make the arithmetic explicit.
Empty is not null
String empty = "";
String missing = null;
System.out.println(empty.length()); // 0
// missing.length() would throw NullPointerException
System.out.println("Hello".equals(missing)); // false
An empty string is still an object. A null reference points to no object, so it has no instance methods to call. Calling equals() on a known non-null literal is useful when the other reference might be null.
The mental model to keep
Treat strings as objects with unusually convenient syntax. Literals make them easy to create, interning allows sharing, and concatenation makes them easy to combine. None of that changes the central rules: variables hold references, string contents are immutable, and text comparisons belong in equals().