Skip to content

String 类

String 是 Java 中最常用的类,用于处理文本。但它的核心特性——不可变性,常常是面试的追问点。

不可变性

String 是不可变类(Immutable)。这意味着:

java
String s = "Hello";
s = "World";  // 不是修改原字符串,而是创建新对象

这里 s 的引用指向了新对象 "World",但 "Hello" 本身从未改变。不可变性带来了两个直接好处:

  1. 线程安全:不可变对象天然支持多线程共享,无需同步
  2. 字符串池优化:相同字面量可以复用,节省内存

创建方式

字面量方式

java
String s1 = "Hello";
String s2 = "Hello";
// s1 和 s2 指向常量池中的同一个对象

字面量创建的字符串会被放入字符串常量池,相同字面量指向同一对象。

new 方式

java
String s3 = new String("Hello");
String s4 = new String("Hello");
// s3 和 s4 是堆中的不同对象

new String() 会在堆中创建新对象,即使字符串内容相同。

java
System.out.println(s1 == s2);  // true(常量池复用)
System.out.println(s1 == s3);  // false(不同对象)
System.out.println(s1.equals(s3));  // true(内容相同)

常用方法

获取长度与字符

java
String s = "Hello";
int length = s.length();  // 5
char c = s.charAt(0);    // 'H'

字符串比较

java
String s1 = "Hello";
String s2 = "hello";

// equals - 区分大小写
System.out.println(s1.equals(s2));  // false

// equalsIgnoreCase - 忽略大小写
System.out.println(s1.equalsIgnoreCase(s2));  // true

// compareTo - 字典顺序,返回差值
System.out.println(s1.compareTo(s2));  // 负数('H' < 'h')

字符串查找

java
String s = "Hello World";

// 查找子串位置
int index = s.indexOf("World");     // 6
int index2 = s.indexOf("o");        // 4(第一个)
int lastIndex = s.lastIndexOf("o"); // 7(最后一个)

// 判断包含
boolean contains = s.contains("World");  // true
boolean starts = s.startsWith("Hello");    // true
boolean ends = s.endsWith("World");        // true

字符串截取

java
String s = "Hello World";

// 截取从索引6到末尾
String sub1 = s.substring(6);        // "World"

// 截取 [0, 5),不包括索引5
String sub2 = s.substring(0, 5);     // "Hello"

字符串转换

java
String s = "Hello World";

// 转大小写
String upper = s.toUpperCase();  // "HELLO WORLD"
String lower = s.toLowerCase();  // "hello world"

// 去除首尾空格
String s2 = "  Hello  ";
String trimmed = s2.trim();      // "Hello"(JDK 11前)
String stripped = s2.strip();   // "Hello"(JDK 11+,处理Unicode空白)

字符串替换

java
String s = "Hello World";

String r1 = s.replaceFirst("o", "X");  // "HellX World"(替换第一个)
String r2 = s.replace("o", "X");        // "HellX WXrld"(替换所有字符)
String r3 = s.replaceAll("World", "Java");  // "Hello Java"(支持正则)

字符串分割

java
String s = "apple,banana,orange";

String[] parts = s.split(",");     // ["apple", "banana", "orange"]
String[] parts2 = s.split(",", 2); // ["apple", "banana,orange"]

// 正则分割:\d 匹配数字
String s2 = "apple1banana2orange";
String[] parts3 = s2.split("\\d"); // ["apple", "banana", "orange"]

字符串拼接

java
// + 拼接
String s1 = "Hello" + " " + "World";

// concat 方法
String s2 = "Hello".concat(" ").concat("World");

// StringBuilder(高效,适合多次拼接)
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(" ").append("World");

// StringJoiner(JDK 8+,适合列表拼接)
StringJoiner joiner = new StringJoiner(", ");
joiner.add("apple").add("banana").add("orange");
String s4 = joiner.toString();  // "apple, banana, orange"

格式化

java
String s = String.format("姓名: %s, 年龄: %d", "张三", 25);
String s2 = String.join(", ", "apple", "banana", "orange");

JDK 11+ 新方法

java
String s = "   Hello World   ";

// isBlank - 判断空白(不只是空串)
"   ".isBlank();       // true
"".isBlank();          // true

// strip 系列 - 处理 Unicode 空白
s.strip();             // 去除首尾空格
s.stripLeading();      // 只去头部
s.stripTrailing();     // 只去尾部

// repeat - 重复字符串
"ab".repeat(3);        // "ababab"

// lines - 按行分割
"line1\nline2\nline3".lines().toList();

字符串比较的坑

java
String s1 = "Hello";
String s2 = new String("Hello");

// ❌ 用 == 比较:比较的是引用,不是内容
System.out.println(s1 == s2);  // false

// ✅ 用 equals 比较:比较的是内容
System.out.println(s1.equals(s2));  // true

记住:引用比较用 ==,内容比较用 equals()

循环拼接的坑

java
// ❌ 循环中用 + 拼接:每次都创建新对象
String result = "";
for (int i = 0; i < 1000; i++) {
    result += "item";  // 效率极低
}

// ✅ 用 StringBuilder:复用同一对象
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("item");
}

编译器虽然会把 += 优化成 StringBuilder,但每次循环都会创建新的 StringBuilder 实例,无法复用。

基于 VitePress 构建