Z
ZHANK
核心类库

字符串 String

掌握 String 不可变性、字符串池、常用方法、StringBuilder

字符串 String

String 是 Java 最常用的类,但它和普通类有个关键区别:String 是不可变的。理解这一点,才能写出高效的字符串代码。

学完本章你将: 掌握 String 不可变性原理、字符串池机制、常用 API、StringBuilder 高效拼接。


String 不可变性

String 内部用 private final byte[] 存储字符,创建后无法修改任何内容。所有看似"修改"字符串的操作(toUpperCasetrim+ 拼接),实际上都在创建新的 String 对象

java
String s1 = "Hello";
String s2 = s1.toUpperCase(); // 不是修改 s1,而是创建新 String
System.out.println(s1);       // "Hello" —— 原字符串纹丝不动
System.out.println(s2);       // "HELLO"

String str = "Java";
str = str + "Script";         // 又是创建新对象,str 指向了新地址

为什么要设计成不可变? 主要三个原因:

  1. 安全:字符串被广泛用作参数(文件路径、网络 URL),不可变意味着不会被意外篡改
  2. 线程安全:多线程随便读,不需要加锁
  3. 字符串池:相同的字符串字面量可以共用同一对象,节省内存

字符串池

JVM 维护了一个「字符串常量池」。当你用双引号 "hello" 创建字符串时,JVM 先去池里找——有就直接返回,没有才创建并放入池中。

java
String a = "hello";
String b = "hello";
System.out.println(a == b);   // true!a 和 b 指向池中同一个对象

new String() 绕过了池,强制在堆上创建新对象:

java
String c = new String("hello");
System.out.println(a == c);   // false!c 是堆上的新对象
System.out.println(a.equals(c)); // true ✅ —— 比较内容要用 equals!

intern() 可以手动把堆上的字符串"请入池":

java
String d = c.intern();        // 尝试入池,若已存在则返回池中的
System.out.println(a == d);   // true

⚠️ 黄金法则: 比较字符串内容永远用 equals()不要用 ==== 比较的是内存地址。


常用方法

java
String s = "  Hello World!  ";

// —— 基本信息 ——
s.length();          // 16(含空格)
s.charAt(6);         // 'H'(索引从 0 开始)

// —— 查找 ——
s.contains("World");  // true
s.indexOf("o");       // 5(第一次出现的位置)
s.lastIndexOf("o");   // 9(最后一次出现)

// —— 提取(都不改变原字符串) ——
s.trim();             // "Hello World!"(去首尾空格)
s.substring(2, 7);    // "Hello"(左闭右开:[2,7))
s.replace("l", "L");  // "  HeLLo WorLd!  "

// —— 分割与拼接 ——
String[] parts = "a,b,c".split(",");       // ["a","b","c"]
String.join("-", parts);                   // "a-b-c"

// —— 判断 ——
s.startsWith("  H");   // true
s.endsWith("!  ");     // true
s.isBlank();           // false(有内容)
"  ".isBlank();        // true(只有空白)
"".isEmpty();          // true(长度为 0)

StringBuilder —— 高效拼接

循环中每次 + 都会创建新 String 对象,如果循环 1000 次就是 1000 个临时对象,严重浪费内存和 CPU。

java
// ❌ 低效:1000 个临时 String 对象
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i;   // 每次 += 都创建新对象!
}

// ✅ 高效:内部用可变的 byte[] 数组,只创建一个对象
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);  // 往同一个数组后追加
}
String result2 = sb.toString();

StringBuilder 常用操作:

java
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
sb.insert(5, " Java");   // 在位置 5 插入 → "Hello Java World"
sb.delete(0, 6);          // 删除 [0,6) → "Java World"
sb.reverse();             // 反转
sb.toString();            // 最后转回 String

💡 选择: 单次拼接用 +(编译器会自动优化为 StringBuilder),循环拼接用 StringBuilder,多线程用 StringBuffer(线程安全但慢)。

StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(i); } String result2 = sb.toString();

// 常用操作 sb.append("Hello") .append(" ") .append("World"); sb.insert(5, " Java"); sb.delete(0, 6); sb.reverse();