深入解析Java String类的核心机制与最佳实践,从不可变性到最新API特性全面剖析。
String作为Java中最常用的类,代表不可变的字符序列。这种不可变性为Java安全模型、字符串常量池和hashCode缓存提供了基础支持。

ObjectSerializable、Comparable<String>和CharSequencepublic final class String定义,禁止被继承// JDK 17 源码(java.lang.String)// 核心字段:存储字符的字节数组
private final byte[] value;// 编码标志:0 = LATIN1(每字符1字节),1 = UTF16(每字符2字节)
private final byte coder;// 哈希值缓存,默认 0,延迟计算
private int hash;// 是否为哈希值 0(极少数真实哈希为 0 的情况下标记用)
private boolean hashIsZero;// 编码常量
static final byte LATIN1 = 0;
static final byte UTF16 = 1;
// 1. 字面量(最常用,走常量池)
String s1 = "hello";// 2. 从 char 数组构造(会复制数组,保证不可变性)
char[] chars = {'h', 'e', 'l', 'l', 'o'};
String s2 = new String(chars);// 3. 从字节数组 + 指定字符集构造
byte[] bytes = "hello".getBytes(StandardCharsets.UTF_8);
String s3 = new String(bytes, StandardCharsets.UTF_8);// 4. 从 StringBuilder / StringBuffer 构造
StringBuilder sb = new StringBuilder("hello");
String s4 = new String(sb);// 5. 静态工厂 valueOf(对 null 友好,返回 "null")
String s5 = String.valueOf(42); // "42"
String s6 = String.valueOf((Object)null); // "null"(不抛 NPE)
equals(Object anObject) — 值相等的判断public boolean equals(Object anObject) {
// 优化1:引用相等直接返回 true(同一对象必然内容相同)
if (this == anObject) {
return true;
}
// 优化2:快速类型检查,非 String 直接返回 false
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value); // 或 StringUTF16.equals
}
实现要点:
this == anObject通过引用比较快速判断instanceof结合模式匹配完成类型检查coder确保编码方式一致hashCode() — 哈希值缓存机制public int hashCode() {
int h = hash;
if (h == 0 && !hashIsZero) {
// 延迟计算:第一次调用时才计算
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true; // 真实哈希为0,打标记避免每次重算
} else {
hash = h; // 缓存结果
}
}
return h;
}
哈希计算公式:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
intern() — 字符串常量池交互public native String intern();
该本地方法由JVM实现:
String a = new String("hello"); // 堆上新对象
String b = "hello"; // 常量池
System.out.println(a == b); // false
System.out.println(a.intern() == b); // true ← intern 后指向同一常量池对象
substring(int beginIndex, int endIndex) — 子串截取public String substring(int beginIndex, int endIndex) {
// 边界检查
int length = length();
checkBoundsBeginEnd(beginIndex, endIndex, length);
// 计算子串长度
int subLen = endIndex - beginIndex;
// 快捷路径:整个字符串
if (beginIndex == 0 && endIndex == length) {
return this;
}
return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
: StringUTF16.newString(value, beginIndex, subLen);
}
String.format / formatted()(JDK 15+)// 传统方式
String result = String.format("Hello, %s! You are %d years old.", "Alice", 30);// JDK 15+ 实例方法(更简洁)
String result2 = "Hello, %s! You are %d years old.".formatted("Alice", 30);
内部使用java.util.Formatter,支持%s(字符串)、%d(整数)、%f(浮点)、%n(换行)等格式符。
| 特性 | JDK 8 | JDK 9–17 |
|---|---|---|
| 内部存储 | char[](固定 2 字节/字符) | byte[] + coder(1 或 2 字节/字符) |
substring | JDK 7u6 起已复制数组 | 同左,无变化 |
String.join | 已引入(JDK 8) | 性能持续优化 |
isBlank/strip | 不存在 | JDK 11 引入,支持 Unicode 空白 |
repeat(int) | 不存在 | JDK 11 引入 |
lines() | 不存在 | JDK 11 引入,返回Stream<String> |
formatted() | 不存在 | JDK 15 引入 |
indent(int) | 不存在 | JDK 12 引入,文本缩进 |
文本块""" | 不支持 | JDK 15 正式发布(JEP 378) |
==比较字符串内容String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false!比较的是引用地址
System.out.println(a.equals(b)); // true
+拼接字符串// 每次循环都创建新 String 对象,O(n²) 复杂度
String result = "";
for (int i = 0; i < 10000; i++) {
result += i;
}// 使用 StringBuilder,O(n) 复杂度
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
String result = sb.toString();
trim()vsstrip()String s = "u3000Hellou3000"; // u3000 是全角空格(Unicode 空白)
System.out.println(s.trim().length()); // 7(没去掉全角空格)
System.out.println(s.strip().length()); // 5(去掉了所有 Unicode 空白)
trim()只处理 ASCII 空白(<= ' '),strip()(JDK 11)使用Character.isWhitespace(),支持 Unicode 空白。
String的"不可变"不等于"线程安全的操作"String对象本身不可变,但对String类型引用变量的读写,在多线程环境下仍需同步(volatile或锁)。
import java.util.StringJoiner;
import java.util.stream.Collectors;public class StringDemo {
public static void main(String[] args) {
// 1. 常量池 vs 堆对象
String poolStr = "java";
String heapStr = new String("java");
System.out.println(poolStr == heapStr); // false
System.out.println(poolStr == heapStr.intern()); // true // 2. JDK 11+ 新 API
String blank = " ";
System.out.println(blank.isBlank()); // true
System.out.println(blank.strip()); // ""
System.out.println("ab".repeat(3)); // "ababab" // 3. 文本块(JDK 15+)
String json = """
{
"name": "Alice",
"age": 30
}
""";
System.out.println(json); // 4. lines() 流式处理
String multiLine = "line1nline2nline3";
multiLine.lines()
.map(String::toUpperCase)
.forEach(System.out::println); // 5. StringJoiner(比手动拼接更优雅)
StringJoiner sj = new StringJoiner(", ", "[", "]");
sj.add("apple").add("banana").add("cherry");
System.out.println(sj); // [apple, banana, cherry] // 6. hashCode 缓存验证
String s = "hello";
System.out.println(s.hashCode()); // 99162322
System.out.println(s.hashCode()); // 99162322(第二次直接返回缓存)
}
}
| 类 | 关系 |
|---|---|
StringBuilder | 可变字符序列,单线程拼接首选 |
StringBuffer | 线程安全版StringBuilder |
StringJoiner | JDK 8 引入,专为分隔符拼接设计 |
java.util.regex.Pattern | String.matches()底层实现 |
java.util.Formatter | String.format()的实际执行者 |
StringConcatFactory | JDK 9+ 编译器拼接优化的核心 |
Charset/StandardCharsets | 字节数组与字符串转换编码 |
java.lang.StringBuilder && StringBuffer下期将深入探讨:
append系列方法源码解析StringConcatFactory优化机制通过本文全面解析Java String类的核心机制与最新特性,帮助开发者深入理解字符串处理的底层原理与最佳实践。