String 类
String 是 Java 中最常用的类,用于处理文本。但它的核心特性——不可变性,常常是面试的追问点。
不可变性
String 是不可变类(Immutable)。这意味着:
java
String s = "Hello";
s = "World"; // 不是修改原字符串,而是创建新对象这里 s 的引用指向了新对象 "World",但 "Hello" 本身从未改变。不可变性带来了两个直接好处:
- 线程安全:不可变对象天然支持多线程共享,无需同步
- 字符串池优化:相同字面量可以复用,节省内存
创建方式
字面量方式
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 实例,无法复用。
