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 不可变的好处 #

  1. 安全性:字符串常用于参数传递,不可变保证数据安全
  2. 线程安全:多个线程可以安全共享
  3. 哈希缓存:hashCode可以缓存,提高性能
  4. 字符串常量池:可以共享相同字符串

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