1. 字符串String基础解析
在Java编程中,String类是最基础也是最常用的类之一。它位于java.lang包下,因此使用时无需额外导入。所有用双引号括起来的文字(如"Hello World")都是String类的实例对象。
重要特性:String对象一旦创建,其内容就不可更改。这种不可变性(immutability)是String类的核心特征,也是很多初学者容易误解的地方。
1.1 String对象的创建方式
Java提供了多种创建String对象的方法,每种方法都有其适用场景:
直接赋值法(最常用):
java复制String str1 = "Java学习笔记";
这种方式会先在字符串常量池中查找是否存在相同内容的字符串,如果存在则直接引用,不存在则在常量池中创建新对象。
构造方法创建:
java复制String str2 = new String(); // 空字符串
String str3 = new String("初始内容"); // 带初始内容
char[] charArray = {'J','a','v','a'};
String str4 = new String(charArray); // 通过字符数组创建
byte[] byteArray = {74, 97, 118, 97};
String str5 = new String(byteArray); // 通过字节数组创建
实际开发建议:除非有特殊需求,否则优先使用直接赋值法。因为这种方式可以利用字符串常量池的优化机制,减少内存消耗。
1.2 字符串不可变性的深层理解
字符串的不可变性意味着:
- 任何看似"修改"字符串的操作(如拼接、替换),实际上都是创建了新的String对象
- 原始字符串对象在内存中保持不变
- 这种设计带来了线程安全、缓存哈希值等优势
java复制String original = "Hello";
original.concat(" World"); // 看似修改,实则创建新对象
System.out.println(original); // 输出仍然是"Hello"
2. String类的核心方法详解
2.1 字符串比较方法
equals()方法 - 严格比较:
java复制String s1 = "Java";
String s2 = new String("Java");
System.out.println(s1.equals(s2)); // true,内容相同
System.out.println(s1 == s2); // false,不是同一个对象
equalsIgnoreCase()方法 - 忽略大小写比较:
java复制String s3 = "JAVA";
System.out.println(s1.equalsIgnoreCase(s3)); // true
避坑指南:永远使用equals()而不是==来比较字符串内容。==比较的是对象引用而非内容。
2.2 字符串遍历与长度获取
length()方法获取字符串长度:
java复制String text = "HelloWorld";
int len = text.length(); // 10
charAt()方法按索引获取字符:
java复制for(int i=0; i<text.length(); i++) {
System.out.println(text.charAt(i));
}
注意:字符串索引从0开始,使用charAt()时要注意索引越界问题。
2.3 字符串截取与替换
substring()方法实现截取:
java复制String origin = "123-456-789";
String part1 = origin.substring(0, 3); // "123"(包头不包尾)
String part2 = origin.substring(4); // "456-789"(从索引4到末尾)
replace()方法实现替换:
java复制String raw = "密码是123456";
String secured = raw.replace("123456", "******");
方法对比表:
| 方法 | 关注点 | 示例 | 返回值 |
|---|---|---|---|
| substring | 位置 | "abc".substring(1) | "bc" |
| replace | 内容 | "aab".replace("a","b") | "bbb" |
3. 字符串处理进阶技巧
3.1 数据脱敏实战
结合substring和replace实现手机号脱敏:
java复制String phone = "13812345678";
String masked = phone.substring(0, 3) + "****" + phone.substring(7);
// 结果:"138****5678"
3.2 敏感词过滤系统
构建简单敏感词过滤器:
java复制String[] badWords = {"暴力", "色情", "赌博"};
String content = "这是一条包含色情的违规内容";
for(String word : badWords) {
if(content.contains(word)) {
content = content.replace(word, "***");
}
}
3.3 其他实用方法
字符串拆分:
java复制String csv = "Java,Python,C++";
String[] languages = csv.split(",");
去除首尾空格:
java复制String input = " user input ";
String trimmed = input.trim(); // "user input"
大小写转换:
java复制String mixed = "JaVa";
String upper = mixed.toUpperCase(); // "JAVA"
String lower = mixed.toLowerCase(); // "java"
4. StringBuilder高效字符串处理
4.1 为什么需要StringBuilder
当需要频繁修改字符串时,String的不可变性会导致大量临时对象产生,影响性能。StringBuilder提供了可变的字符串缓冲区。
性能对比测试:
java复制// 使用String拼接
long start = System.currentTimeMillis();
String result = "";
for(int i=0; i<10000; i++) {
result += i;
}
long end = System.currentTimeMillis();
System.out.println("String耗时:" + (end-start) + "ms");
// 使用StringBuilder
start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for(int i=0; i<10000; i++) {
sb.append(i);
}
end = System.currentTimeMillis();
System.out.println("StringBuilder耗时:" + (end-start) + "ms");
4.2 StringBuilder核心API
基本操作:
java复制StringBuilder sb = new StringBuilder("初始");
sb.append("内容"); // 追加
sb.insert(1, "在索引1处插入"); // 插入
sb.delete(1, 3); // 删除
sb.reverse(); // 反转
String finalStr = sb.toString(); // 转为String
链式调用:
java复制String str = new StringBuilder()
.append("第一部分")
.append("第二部分")
.insert(2, "插入内容")
.toString();
4.3 使用场景建议
适合使用StringBuilder的场景:
- 循环体内字符串拼接
- 需要频繁修改的大文本处理
- 动态生成SQL语句
- 构建复杂的字符串输出
经验之谈:在单线程环境下优先使用StringBuilder,它的性能比StringBuffer更好。只有在多线程环境下才考虑使用线程安全的StringBuffer。
5. 字符串处理中的常见陷阱
5.1 编码问题
字符编码转换:
java复制String str = "中文";
try {
byte[] utf8Bytes = str.getBytes("UTF-8");
String newStr = new String(utf8Bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
重要提示:在不同系统间传输字符串时,务必明确指定编码方式,避免因默认编码不同导致乱码。
5.2 性能优化
预分配StringBuilder容量:
java复制// 不佳做法:默认容量不足时会频繁扩容
StringBuilder sb1 = new StringBuilder();
// 优化做法:预估最终大小
StringBuilder sb2 = new StringBuilder(1024); // 初始容量1024
5.3 正则表达式应用
复杂字符串匹配:
java复制String input = "用户邮箱:test@example.com";
String emailRegex = "\\w+@\\w+\\.\\w+";
Pattern pattern = Pattern.compile(emailRegex);
Matcher matcher = pattern.matcher(input);
if(matcher.find()) {
System.out.println("找到邮箱:" + matcher.group());
}
6. 字符串最佳实践总结
- 不变性原则:牢记String的不可变性,理解所有"修改"操作实际都创建新对象
- 比较规范:总是使用equals()比较内容,而非==
- 拼接选择:
- 少量拼接:使用+运算符
- 循环或多处拼接:使用StringBuilder
- 内存优化:
- 重用不变的字符串
- 对可能重复使用的字符串使用intern()方法
- 安全处理:
- 用户输入总是先trim()再处理
- 敏感信息及时脱敏
- 编码明确:
- 在IO操作中明确指定字符编码
- 避免依赖平台默认编码
在实际项目中,我曾遇到一个因不当使用字符串拼接导致的性能问题:一个生成大型报表的功能,最初使用String拼接,当数据量达到万级时,生成时间超过10分钟。改用StringBuilder优化后,时间缩短到10秒以内。这个教训让我深刻理解了字符串处理性能的重要性。