JavaSE 字符串:深入解析 String
、StringBuilder
与 StringBuffer
一、字符串的核心类
1. String
类(不可变)
- 特性:
- 底层使用
final char[]
存储(Java 9+ 改为byte[]
),不可变(Immutable)。 - 每次操作都会生成新的
String
对象,性能开销大。
- 底层使用
- 示例:
String s1 = "Hello"; // 字面量创建(存储在字符串常量池) String s2 = new String("Hello"); // 对象创建(堆内存) String s3 = s1 + " World"; // 拼接操作生成新对象
2. StringBuilder
类(可变)
- 特性:
- 线程不安全,性能高(无同步开销)。
- 推荐在单线程环境下使用。
- 示例:
StringBuilder sb = new StringBuilder(); sb.append("Hello").append(" World"); // 直接修改原对象 String result = sb.toString(); // 转换为String
3. StringBuffer
类(可变)
- 特性:
- 线程安全(方法使用
synchronized
修饰),性能较低。 - 推荐在多线程环境下使用。
- 线程安全(方法使用
- 示例:
StringBuffer sb = new StringBuffer(); sb.append("Hello").append(" World"); // 线程安全的操作
二、字符串常量池(String Pool)
-
作用:避免重复创建相同的字符串对象,提高内存效率。
-
示例:
String s1 = "abc"; // 常量池创建"abc" String s2 = "abc"; // 复用常量池中的对象 System.out.println(s1 == s2); // true(引用相同)String s3 = new String("abc"); // 堆内存创建新对象 System.out.println(s1 == s3); // false(引用不同)
-
intern()
方法:
将字符串对象添加到常量池并返回池中的引用。String s4 = s3.intern(); // 将s3的内容添加到常量池 System.out.println(s1 == s4); // true
三、字符串操作的性能优化
-
避免循环内使用
+
拼接:// 低效(每次循环生成新对象) String result = ""; for (int i = 0; i < 1000; i++) {result += i; }// 高效(使用StringBuilder) StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) {sb.append(i); }
-
预分配
StringBuilder
容量:StringBuilder sb = new StringBuilder(1000); // 预分配容量,减少扩容次数
四、字符串常用方法
方法 | 描述 |
---|---|
length() | 返回字符串长度。 |
charAt(int index) | 返回指定位置的字符。 |
substring(int start, int end) | 返回子串(左闭右开)。 |
equals(Object obj) | 比较字符串内容是否相等(区分大小写)。 |
equalsIgnoreCase(String another) | 比较字符串内容(忽略大小写)。 |
contains(CharSequence s) | 判断是否包含指定字符序列。 |
indexOf(String s) | 返回子串首次出现的索引(不存在返回-1)。 |
lastIndexOf(String s) | 返回子串最后一次出现的索引。 |
startsWith(String prefix) | 判断是否以指定前缀开头。 |
endsWith(String suffix) | 判断是否以指定后缀结尾。 |
toUpperCase() /toLowerCase() | 转换大小写。 |
trim() | 去除字符串前后的空白字符。 |
replace(char old, char new) | 替换所有匹配的字符。 |
split(String regex) | 根据正则表达式分割字符串,返回数组。 |
join(CharSequence delimiter, CharSequence... elements) | 静态方法,用分隔符连接多个字符串。 |
五、字符串与编码
- 常见编码格式:
UTF-8
、GBK
、ISO-8859-1
。 - 编码转换:
String str = "你好"; byte[] utf8Bytes = str.getBytes("UTF-8"); // 字符串转字节(UTF-8编码) String newStr = new String(utf8Bytes, "UTF-8"); // 字节转字符串(指定编码)
六、字符串的正则表达式应用
-
匹配验证:
boolean isEmail = "test@example.com".matches("^[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z]{2,}$");
-
替换:
String text = "a1b2c3"; String result = text.replaceAll("\\d", "*"); // 替换所有数字为*
-
分割:
String[] parts = "a,b;c d".split("[,;\\s]+"); // 按逗号、分号或空格分割
七、面试常见问题
-
String
为什么是不可变的?- 安全考虑(如参数传递、类加载器)。
- 支持字符串常量池,提高性能。
- 线程安全(不可变对象天然线程安全)。
-
StringBuilder
与StringBuffer
的区别?StringBuilder
线程不安全,性能高;StringBuffer
线程安全,性能低。
-
以下代码创建了几个对象?
String s = new String("abc");
- 2个:一个在常量池(“abc”),一个在堆内存(
new String()
)。
- 2个:一个在常量池(“abc”),一个在堆内存(
-
如何优化大量字符串拼接?
- 使用
StringBuilder
(单线程)或StringBuffer
(多线程),避免使用+
。
- 使用
八、最佳实践
- 优先使用
StringBuilder
:在非线程安全场景下替代StringBuffer
。 - 字符串常量拼接使用
+
:编译器会自动优化为StringBuilder
。 - 避免
String
与基本类型频繁转换:使用String.valueOf()
或包装类的toString()
。
合理使用字符串相关类,能有效提升代码性能和安全性。