Java Language Specification — Strings and Methods Source: https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.10.5 1. Spec Reference JLS §3.10.5 : String Literals — https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.10.5 JLS §3.10.6 : Text Blocks — https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.10.6 JLS §4.3.3 : The Class String — https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.3.3 JLS §8.4 : Method Declarations — https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.4 JLS §8.4.1 : Formal Parameters JLS §8.4.2 : Method Signature JLS §8.4.3 : Method Modifiers JLS §8.4.4 : Generic Methods JLS §8.4.5 : Method Return Type JLS §8.4.6 : Method Throws JLS §8.4.7 : Method Body JLS §8.4.8 : Inheritance, Overriding, Hiding JLS §15.18.1 : String Concatenation Operator + JLS §15.28 : String Switch Expressions -- JLS §3.10.5: String Literal --
StringLiteral:
" {StringCharacter} "
StringCharacter:
InputCharacter but not " or \
EscapeSequence
EscapeSequence:
\ b (backspace U+0008)
\ t (tab U+0009)
\ n (newline U+000A)
\ f (form feed U+000C)
\ r (carriage return U+000D)
\ " (double quote U+0022)
\ ' (single quote U+0027)
\ \ (backslash U+005C)
\ s (space U+0020) [Java 15+]
\ LineTerminator [line continuation, Java 15+]
OctalEscape
OctalEscape:
\ OctalDigit
\ OctalDigit OctalDigit
\ ZeroToThree OctalDigit OctalDigit
-- JLS §3.10.6: Text Block --
TextBlock:
""" {WhiteSpace} LineTerminator {TextBlockCharacter} """
TextBlockCharacter:
InputCharacter but not \
EscapeSequence
LineTerminator
-- JLS §8.4: Method Declaration --
MethodDeclaration:
{MethodModifier} MethodHeader MethodBody
MethodHeader:
Result MethodDeclarator [Throws]
TypeParameters {Annotation} Result MethodDeclarator [Throws]
MethodDeclarator:
Identifier ( [ReceiverParameter ,] [FormalParameterList] ) [Dims]
Result:
UnannType
void
FormalParameterList:
FormalParameter { , FormalParameter }
FormalParameter:
{VariableModifier} UnannType VariableDeclaratorId
VariableArityParameter
VariableArityParameter:
{VariableModifier} UnannType {Annotation} ... Identifier
MethodModifier:
Annotation
public | protected | private
abstract | static | final
synchronized | native | strictfp
Throws:
throws ExceptionTypeList
ExceptionTypeList:
ExceptionType { , ExceptionType }
ExceptionType:
ClassType
TypeVariable
MethodBody:
Block
;
-- JLS §15.18.1: String Concatenation --
-- When + is applied to a String operand, it becomes string concatenation.
-- Non-string operands are converted via String.valueOf().
-- The JLS permits the compiler to use StringBuilder or StringConcatFactory.
3. Core Rules & Constraints 3.1 String Immutability (JLS §4.3.3) String objects are immutable — once created, their content cannot be changed. All String methods that appear to "modify" return new String instances. The String class is declared final — cannot be subclassed. String implements CharSequence, Comparable<String>, and Serializable. 3.2 String Interning (JLS §3.10.5) String literals are automatically interned (JLS §3.10.5, §4.3.3). All references to the same string literal refer to the same String object. "hello" == "hello" is true (both interned). new String("hello") == "hello" is false (new object not interned by default). String.intern() returns the canonical interned instance. 3.3 String Concatenation (JLS §15.18.1) If either operand is a String, + becomes string concatenation. null operands are converted to the string "null". The expression is evaluated left to right. javac may optimize using StringBuilder or invokedynamic with StringConcatFactory (Java 9+). 3.4 Text Blocks (JLS §3.10.6, Java 15+) Opening """ must be followed by a line terminator. The closing """ determines the re-indentation anchor. Incidental whitespace (common indentation) is stripped. Trailing whitespace on each line is stripped unless escaped with \s. \ at end of line is a line-continuation escape — no newline inserted. 3.5 Method Declaration Rules (JLS §8.4) abstract methods have no body (semicolon only); non-abstract methods must have a body. native methods have no Java body; implemented in native code. synchronized methods acquire the object's (or class's, if static) monitor before execution. Varargs (...) must be the last parameter; only one varargs per method. Method overloading: same name, different parameter types (not just return type). 3.6 Method Overriding (JLS §8.4.8) Override requires: same name, same parameter types, return type is covariant (same or subtype). @Override annotation is not required but triggers a compile error if the method does NOT override. Overriding method's access modifier cannot be more restrictive than overridden method. Overriding method cannot declare new checked exceptions not declared by the overridden method. 4. Type Rules 4.1 Return Type Covariance (JLS §8.4.5) An overriding method may declare a return type that is a subtype of the overridden method's return type. Example: Object clone() in Object can be overridden as Foo clone() in Foo. This is called covariant return types (added in Java 5). 4.2 Method Signature (JLS §8.4.2) Signature consists of: method name + number and types of formal parameters (NOT return type, NOT thrown exceptions). Two methods with same name and parameter types are the same signature. Same signature methods cannot coexist in the same class (compile error) — unless one is bridge method (synthetic). 4.3 Varargs Type Rules (JLS §8.4.1) void f(int... args) is equivalent to void f(int[] args) in the bytecode. f(1, 2, 3) compiles to f(new int[]{1, 2, 3}). f() compiles to f(new int[]{}). Cannot overload f(int[]) and f(int...) — same erasure. 4.4 Generic Methods (JLS §8.4.4) Type parameters declared before return type: <T> List<T> singletonList(T t). Type inference resolves T from arguments at call site. Bounds: <T extends Comparable<T>> T max(T a, T b). 5. Behavioral Specification 5.1 String Comparison Behavior == compares object references (identity). .equals() compares content (character-by-character). .equalsIgnoreCase() compares content ignoring case differences. .compareTo() returns lexicographic order (negative, 0, positive). .compareToIgnoreCase() — case-insensitive lexicographic order. 5.2 Core String Methods (from java.lang.String API) Method Description Returns length() Number of UTF-16 code units int charAt(int) Code unit at index char codePointAt(int) Unicode code point at index int substring(int, int) Subsequence String indexOf(String) First occurrence int (-1 if not found) contains(CharSequence) Membership check boolean replace(CharSequence, CharSequence) Literal replacement (all occurrences) String replaceAll(String, String) Regex replacement String split(String) Splits by regex String[] strip() Removes leading/trailing whitespace (Unicode-aware, Java 11+) String trim() Removes ASCII whitespace (legacy) String toUpperCase() Uppercase (locale-sensitive) String toLowerCase() Lowercase (locale-sensitive) String isEmpty() Length == 0 boolean isBlank() All whitespace or empty (Java 11+) boolean chars() Stream of code units (Java 8+) IntStream codePoints() Stream of code points (Java 8+) IntStream formatted(Object...) Like String.format (Java 15+) String repeat(int) Repeat n times (Java 11+) String indent(int) Adjust indentation (Java 12+) String translateEscapes() Interpret \n, \t etc. in string (Java 15+) String
5.3 Method Invocation (JLS §15.12) Identify potentially applicable methods (by name and arity). Identify applicable methods (by type compatibility with actual args). Choose most specific applicable method. If two methods are equally specific and neither overrides the other → ambiguous compile error. 6. Defined vs Undefined Behavior Situation Behavior per JLS "hello" + null "hellonull" null + "hello" "nullhello" "hello" == "hello" true (interned literals) new String("hello") == "hello" false s.charAt(s.length()) StringIndexOutOfBoundsException s.substring(-1, 3) StringIndexOutOfBoundsException s.substring(3, 1) StringIndexOutOfBoundsException Concatenation with null reference "null" string representation String.format(null, args) NullPointerException Method overriding with throws Can only reduce checked exceptions, not add new ones
7. Edge Cases from Spec 7.1 String Concatenation with null String s = null ;
System . out . println ( "value: " + s ); // "value: null"
System . out . println ( s + " there" ); // "null there"
Object obj = null ;
String result = "" + obj ; // "null"
7.2 String Literal Interning String a = "hello" ;
String b = "hello" ;
String c = new String ( "hello" );
String d = c . intern ();
System . out . println ( a == b ); // true (same interned literal)
System . out . println ( a == c ); // false (c is new object)
System . out . println ( a == d ); // true (d is interned)
System . out . println ( a . equals ( c )); // true (same content)
7.3 Text Block Indentation // The closing """ at column 8 determines indentation removal
String json = """
{
"name": "Java"
}
""" ;
// Result: "{\n \"name\": \"Java\"\n}\n"
// 8 spaces of indentation stripped from each line
7.4 Varargs Ambiguity static void print ( Object ... args ) { System . out . println ( "varargs Object" ); }
static void print ( String s ) { System . out . println ( "exact String" ); }
print ( "hello" ); // calls exact String version (more specific)
print (( Object ) "hello" ); // calls varargs Object version
7.5 Covariant Return Type Override class Animal {
Animal create () { return new Animal (); }
}
class Dog extends Animal {
@Override
Dog create () { return new Dog (); } // covariant return: Dog is subtype of Animal
}
7.6 Method Hiding vs Overriding class Parent {
static String type () { return "Parent" ; } // class method
String name () { return "Parent" ; } // instance method
}
class Child extends Parent {
static String type () { return "Child" ; } // HIDES (not overrides) static method
@Override String name () { return "Child" ; } // OVERRIDES instance method
}
// Parent p = new Child();
// p.type() → "Parent" (hidden, resolved at compile time)
// p.name() → "Child" (overridden, resolved at runtime)
8. Version History Java Version Change JEP/Reference Java 1.0 String, string literals, concatenation with + JLS 1st ed. Java 5 Covariant return types; generics methods; varargs JSR 14 Java 7 switch on String JLS §14.11 Java 9 StringConcatFactory (invokedynamic for +) JEP 280 Java 11 strip(), isBlank(), lines(), repeat() JDK-11 API Java 12 indent(), transform() JDK-12 API Java 13 Text blocks (preview) JEP 355 Java 14 Text blocks (2nd preview) JEP 368 Java 15 Text blocks (standard); formatted(), translateEscapes() JEP 378 Java 15 \s and \<line-terminator> escape sequences JEP 378 Java 21 String.indexOf(String, int, int) new overload JDK-21 API
9. Implementation-Specific Behavior (JVM-Specific) 9.1 String Concatenation Optimization (JEP 280, Java 9+) javac compiles s1 + s2 + s3 using invokedynamic calling StringConcatFactory.makeConcatWithConstants. The JVM decides at runtime how to best concatenate strings. HotSpot uses StringBuilder-like strategies internally. Avoids creating intermediate String objects for each +. 9.2 String Deduplication JVM G1GC can deduplicate String objects (same content → share char array). Enabled with -XX:+UseStringDeduplication. Does NOT make == comparisons reliable — use .equals(). 9.3 Compact Strings (JEP 254, Java 9+) Strings containing only Latin-1 characters are stored as byte[] instead of char[]. Reduces memory footprint by ~50% for typical ASCII-heavy workloads. Transparent to Java code; no behavior change. 9.4 Virtual Method Dispatch Instance methods are dispatched via invokevirtual (dynamic dispatch through vtable). private, final, and static methods use invokespecial or invokestatic (no virtual dispatch). Interface methods use invokeinterface. 10. Spec Compliance Checklist 11. Official Examples (Compilable Java 21 Code) // Example 1: String Fundamentals
// File: StringFundamentals.java
public class StringFundamentals {
public static void main ( String [] args ) {
// Immutability
String s1 = "Hello" ;
String s2 = s1 . concat ( ", World" ); // new String created; s1 unchanged
System . out . println ( "s1: " + s1 ); // Hello
System . out . println ( "s2: " + s2 ); // Hello, World
// Reference equality vs content equality
String a = "Java" ;
String b = "Java" ;
String c = new String ( "Java" );
System . out . println ( a == b ); // true (interned literals)
System . out . println ( a == c ); // false (new object)
System . out . println ( a . equals ( c )); // true (same content)
System . out . println ( a . equals ( null )); // false (no NPE)
// Key methods
String str = " Hello, World! " ;
System . out . println ( str . strip ()); // "Hello, World!"
System . out . println ( str . trim ()); // "Hello, World!"
System . out . println ( "hello" . toUpperCase ()); // "HELLO"
System . out . println ( "HELLO" . toLowerCase ()); // "hello"
System . out . println ( " " . isBlank ()); // true
System . out . println ( "hello" . contains ( "ell" )); // true
System . out . println ( "hello" . startsWith ( "hel" )); // true
System . out . println ( "hello" . endsWith ( "llo" )); // true
System . out . println ( "hello" . indexOf ( 'l' )); // 2
System . out . println ( "hello" . lastIndexOf ( 'l' )); // 3
System . out . println ( "hello" . replace ( "l" , "r" )); // "herro"
System . out . println ( "a,b,c" . split ( "," ). length ); // 3
System . out . println ( "ha" . repeat ( 3 )); // "hahaha"
}
}
// Example 2: Text Blocks (Java 15+)
// File: TextBlockDemo.java
public class TextBlockDemo {
public static void main ( String [] args ) {
// JSON text block
String json = """
{
"name": "Alice",
"age": 30
}
""" ;
System . out . println ( json );
// HTML text block
String html = """
<html>
<body>
<p>Hello, World!</p>
</body>
</html>
""" ;
System . out . println ( html );
// Escape sequences in text blocks
String withEscape = """
Line 1\s
Line 2\s
""" ;
// \s preserves trailing space on each line
// Line continuation
String singleLine = """
This is a \
single line\
""" ;
System . out . println ( singleLine ); // "This is a single line"
// formatted() (Java 15+) — equivalent to String.format()
String template = """
Name: %s
Score: %.2f
""" . formatted ( "Bob" , 95.5 );
System . out . println ( template );
}
}
// Example 3: Method Declarations
// File: MethodDeclarations.java
import java.util.Arrays ;
public class MethodDeclarations {
// Static method
static int add ( int a , int b ) { return a + b ; }
// Instance method
String greet ( String name ) { return "Hello, " + name ; }
// Varargs method
static int sum ( int ... numbers ) {
int total = 0 ;
for ( int n : numbers ) total += n ;
return total ;
}
// Generic method
static < T extends Comparable < T >> T max ( T a , T b ) {
return a . compareTo ( b ) >= 0 ? a : b ;
}
// Method with throws clause
static int parseInt ( String s ) throws NumberFormatException {
return Integer . parseInt ( s );
}
// Covariant return type
static class Builder {
String value = "" ;
Builder append ( String s ) { value += s ; return this ; } // returns Builder for chaining
}
// Method overloading
static String format ( int n ) { return "int: " + n ; }
static String format ( double d ) { return "double: " + d ; }
static String format ( String s ) { return "string: " + s ; }
public static void main ( String [] args ) {
System . out . println ( add ( 3 , 4 ));
System . out . println ( sum ( 1 , 2 , 3 , 4 , 5 )); // varargs
System . out . println ( sum ()); // empty varargs → 0
System . out . println ( max ( "apple" , "banana" )); // generic method
System . out . println ( max ( 10 , 20 ));
// Method chaining with builder
Builder b = new Builder ();
b . append ( "Hello" ). append ( ", " ). append ( "World!" );
System . out . println ( b . value );
// Overloaded method resolution
System . out . println ( format ( 42 ));
System . out . println ( format ( 3.14 ));
System . out . println ( format ( "test" ));
}
}
// Example 4: StringBuilder for Mutable Strings
// File: StringBuilderDemo.java
public class StringBuilderDemo {
public static void main ( String [] args ) {
// StringBuilder: mutable character sequence
StringBuilder sb = new StringBuilder ();
sb . append ( "Hello" );
sb . append ( ", " );
sb . append ( "World" );
sb . append ( "!" );
System . out . println ( sb . toString ()); // Hello, World!
System . out . println ( sb . length ()); // 13
System . out . println ( sb . charAt ( 0 )); // H
sb . insert ( 5 , " Beautiful" ); // insert at index
System . out . println ( sb ); // Hello Beautiful, World!
sb . delete ( 5 , 15 ); // delete range
System . out . println ( sb ); // Hello, World!
sb . reverse ();
System . out . println ( sb ); // !dlroW ,olleH
// Building strings in a loop — use StringBuilder, not +
long start = System . nanoTime ();
StringBuilder csv = new StringBuilder ();
for ( int i = 0 ; i < 10_000 ; i ++ ) {
csv . append ( i ). append ( ',' );
}
long end = System . nanoTime ();
System . out . printf ( "Built %d chars in %d µs%n" ,
csv . length (), ( end - start ) / 1000 );
}
}
// Example 5: Method Overriding and toString()
// File: MethodOverriding.java
import java.util.Objects ;
public class MethodOverriding {
static class Point {
final double x , y ;
Point ( double x , double y ) {
this . x = x ;
this . y = y ;
}
@Override
public String toString () {
return "Point(%s, %s)" . formatted ( x , y );
}
@Override
public boolean equals ( Object obj ) {
if ( this == obj ) return true ;
if ( ! ( obj instanceof Point other )) return false ;
return Double . compare ( x , other . x ) == 0
&& Double . compare ( y , other . y ) == 0 ;
}
@Override
public int hashCode () {
return Objects . hash ( x , y );
}
// Covariant return
Point translate ( double dx , double dy ) {
return new Point ( x + dx , y + dy );
}
}
static class Point3D extends Point {
final double z ;
Point3D ( double x , double y , double z ) {
super ( x , y );
this . z = z ;
}
@Override
public String toString () {
return "Point3D(%s, %s, %s)" . formatted ( x , y , z );
}
@Override
Point3D translate ( double dx , double dy ) { // covariant return
return new Point3D ( x + dx , y + dy , z );
}
}
public static void main ( String [] args ) {
Point p = new Point ( 1.0 , 2.0 );
System . out . println ( p ); // Point(1.0, 2.0)
System . out . println ( p . translate ( 1 , 1 )); // Point(2.0, 3.0)
Point3D p3 = new Point3D ( 1.0 , 2.0 , 3.0 );
System . out . println ( p3 ); // Point3D(1.0, 2.0, 3.0)
// Polymorphism via toString
Point ref = p3 ;
System . out . println ( ref . toString ()); // Point3D(1.0, 2.0, 3.0)
// equals
System . out . println ( p . equals ( new Point ( 1.0 , 2.0 ))); // true
System . out . println ( p . equals ( p3 )); // false (z differs)
}
}
Section Topic URL JLS §3.10.5 String Literals https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.10.5 JLS §3.10.6 Text Blocks https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.10.6 JLS §4.3.3 Class String https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.3.3 JLS §8.4 Method Declarations https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.4 JLS §8.4.8 Overriding https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.4.8 JLS §15.12 Method Invocation https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.12 JLS §15.18.1 String Concatenation https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.18.1 JEP 280 Indify String Concatenation https://openjdk.org/jeps/280 JEP 378 Text Blocks https://openjdk.org/jeps/378 JEP 254 Compact Strings https://openjdk.org/jeps/254
In this topic