Java字符串 #
一、字符串概述 #
字符串是一系列字符的序列,在Java中用String类表示。字符串是Java中最常用的数据类型之一。
1.1 字符串特点 #
- 字符串是不可变的(Immutable)
- 字符串是引用类型
- 字符串可以被共享
- 字符串本质是char数组
二、字符串创建 #
2.1 直接创建 #
java
String s1 = "Hello";
String s2 = "World";
String s3 = "Hello"; // s1和s3指向同一个对象
2.2 使用构造方法 #
java
// 无参构造
String s1 = new String();
// 从字符串创建
String s2 = new String("Hello");
// 从字符数组创建
char[] chars = {'H', 'e', 'l', 'l', 'o'};
String s3 = new String(chars);
// 从字节数组创建
byte[] bytes = {72, 101, 108, 108, 111};
String s4 = new String(bytes);
2.3 字符串常量池 #
java
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); // true(同一对象)
System.out.println(s1 == s3); // false(不同对象)
System.out.println(s1.equals(s3)); // true(内容相同)
// intern方法:返回常量池中的引用
String s4 = s3.intern();
System.out.println(s1 == s4); // true
三、字符串不可变性 #
3.1 什么是不可变 #
字符串一旦创建,其内容不能被修改。
java
String s = "Hello";
s = s + " World"; // 创建了新字符串对象
// 内存中:
// "Hello" 仍然存在
// "Hello World" 是新创建的
3.2 不可变的好处 #
- 安全性:字符串常用于参数传递,不可变保证数据安全
- 线程安全:多个线程可以安全共享
- 哈希缓存:hashCode可以缓存,提高性能
- 字符串常量池:可以共享相同字符串
3.3 源码分析 #
java
// String类源码(简化)
public final class String {
private final char[] value; // JDK 8
// private final byte[] value; // JDK 9+
// 没有提供修改内容的方法
}
四、字符串常用方法 #
4.1 获取信息 #
java
String s = "Hello World";
// 长度
int len = s.length(); // 11
// 获取字符
char c = s.charAt(0); // 'H'
// char c2 = s.charAt(20); // StringIndexOutOfBoundsException
// 获取字节数组
byte[] bytes = s.getBytes();
// 获取字符数组
char[] chars = s.toCharArray();
// 空判断
boolean empty = s.isEmpty(); // false
boolean blank = s.isBlank(); // false(JDK 11+)
4.2 查找方法 #
java
String s = "Hello World";
// 查找字符/子串位置
int idx1 = s.indexOf('o'); // 4
int idx2 = s.indexOf("World"); // 6
int idx3 = s.indexOf('o', 5); // 7(从位置5开始)
// 从后查找
int idx4 = s.lastIndexOf('o'); // 7
// 是否包含
boolean contains = s.contains("World"); // true
// 是否以指定前缀/后缀开头/结尾
boolean starts = s.startsWith("Hello"); // true
boolean ends = s.endsWith("World"); // true
4.3 截取方法 #
java
String s = "Hello World";
// 从指定位置截取到末尾
String sub1 = s.substring(6); // "World"
// 截取指定范围 [begin, end)
String sub2 = s.substring(0, 5); // "Hello"
4.4 替换方法 #
java
String s = "Hello World";
// 替换字符
String r1 = s.replace('o', 'O'); // "HellO WOrld"
// 替换字符串
String r2 = s.replace("World", "Java"); // "Hello Java"
// 正则替换
String r3 = s.replaceAll("o", "O");
String r4 = s.replaceFirst("o", "O"); // 只替换第一个
// 删除空白
String text = " Hello World ";
String trim = text.trim(); // "Hello World"
String strip = text.strip(); // "Hello World"(JDK 11+)
String stripLead = text.stripLeading(); // "Hello World "
String stripTrail = text.stripTrailing(); // " Hello World"
4.5 大小写转换 #
java
String s = "Hello World";
String upper = s.toUpperCase(); // "HELLO WORLD"
String lower = s.toLowerCase(); // "hello world"
4.6 分割与连接 #
java
// 分割
String csv = "apple,banana,orange";
String[] fruits = csv.split(",");
// ["apple", "banana", "orange"]
// 限制分割次数
String[] parts = "a,b,c,d".split(",", 2);
// ["a", "b,c,d"]
// 连接(JDK 8+)
String joined = String.join("-", "a", "b", "c"); // "a-b-c"
String joined2 = String.join(",", fruits); // "apple,banana,orange"
4.7 比较方法 #
java
String s1 = "Hello";
String s2 = "hello";
// 内容比较
boolean eq1 = s1.equals(s2); // false
boolean eq2 = s1.equalsIgnoreCase(s2); // true
// 大小比较(字典序)
int cmp = s1.compareTo(s2); // -32(H < h)
int cmp2 = s1.compareToIgnoreCase(s2); // 0
// 前缀匹配
boolean matches = s1.matches("H.*"); // true
4.8 格式化 #
java
// String.format
String s1 = String.format("姓名: %s, 年龄: %d", "张三", 25);
// "姓名: 张三, 年龄: 25"
String s2 = String.format("价格: %.2f", 99.999);
// "价格: 100.00"
// formatted方法(JDK 15+)
String s3 = "姓名: %s, 年龄: %d".formatted("李四", 30);
五、StringBuilder和StringBuffer #
5.1 为什么需要StringBuilder #
字符串不可变,频繁拼接会产生大量临时对象:
java
// 效率低
String s = "";
for (int i = 0; i < 1000; i++) {
s += i; // 每次都创建新对象
}
// 效率高
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();
5.2 StringBuilder #
StringBuilder是可变字符串,线程不安全,效率高。
java
// 创建
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder(100); // 指定初始容量
StringBuilder sb3 = new StringBuilder("Hello");
// 追加
sb1.append("Hello");
sb1.append(" ");
sb1.append("World");
sb1.append(123); // 可以追加任意类型
// 插入
sb1.insert(5, ",");
// 删除
sb1.delete(5, 6); // 删除指定范围
sb1.deleteCharAt(5); // 删除指定位置
// 替换
sb1.replace(0, 5, "Hi");
// 反转
sb1.reverse();
// 转为String
String s = sb1.toString();
// 获取长度和容量
int len = sb1.length();
int cap = sb1.capacity();
5.3 StringBuffer #
StringBuffer是可变字符串,线程安全,效率略低。
java
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(" World");
// 方法与StringBuilder相同
String result = sb.toString();
5.4 对比 #
| 特性 | String | StringBuilder | StringBuffer |
|---|---|---|---|
| 可变性 | 不可变 | 可变 | 可变 |
| 线程安全 | 安全 | 不安全 | 安全 |
| 效率 | 低(拼接) | 高 | 中等 |
| 适用场景 | 少量字符串 | 单线程拼接 | 多线程拼接 |
六、字符串处理技巧 #
6.1 判断空字符串 #
java
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
public static boolean isBlank(String str) {
return str == null || str.isBlank(); // JDK 11+
}
// 或使用Apache Commons Lang
// StringUtils.isEmpty(str)
// StringUtils.isBlank(str)
6.2 字符串拼接 #
java
// 少量拼接:直接用+
String s = "Hello" + " " + "World";
// 循环拼接:用StringBuilder
StringBuilder sb = new StringBuilder();
for (String item : list) {
sb.append(item).append(",");
}
// 删除最后的逗号
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
}
// 使用String.join(JDK 8+)
String joined = String.join(",", list);
6.3 字符串反转 #
java
// 方法1:StringBuilder
String reversed = new StringBuilder(s).reverse().toString();
// 方法2:手动实现
public static String reverse(String s) {
char[] chars = s.toCharArray();
int left = 0, right = chars.length - 1;
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
return new String(chars);
}
6.4 判断回文 #
java
public static boolean isPalindrome(String s) {
if (s == null) return false;
int left = 0, right = s.length() - 1;
while (left < right) {
if (s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
七、常见问题 #
7.1 字符串比较 #
java
String s1 = new String("Hello");
String s2 = new String("Hello");
// 错误:使用==比较
if (s1 == s2) { } // false
// 正确:使用equals比较
if (s1.equals(s2)) { } // true
// 安全比较(避免NPE)
if (s1 != null && s1.equals(s2)) { }
// 或
if (Objects.equals(s1, s2)) { }
7.2 字符串拼接效率 #
java
// 低效
String s = "";
for (int i = 0; i < 10000; i++) {
s += i;
}
// 高效
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
String s = sb.toString();
7.3 编码问题 #
java
// 指定编码
String s = "你好";
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
String decoded = new String(bytes, StandardCharsets.UTF_8);
// 旧方式(不推荐)
// byte[] bytes = s.getBytes("UTF-8");
八、总结 #
| 类 | 特点 | 使用场景 |
|---|---|---|
| String | 不可变、安全 | 少量字符串、常量 |
| StringBuilder | 可变、非线程安全 | 单线程大量拼接 |
| StringBuffer | 可变、线程安全 | 多线程大量拼接 |
字符串要点:
- String是不可变的
- 使用equals比较内容
- 大量拼接用StringBuilder
- 注意编码问题
- 善用字符串方法
最后更新:2026-03-26