方法定义

public void setCharAt(int index, char ch)

核心功能

  1. 字符级修改
    直接修改指定索引位置的字符(char类型)
  2. 原地操作
    直接修改当前StringBuilder对象,不创建新对象
  3. 高效修改
    时间复杂度 O(1),远优于字符串替换操作

参数说明

参数 类型 必需 说明
index int 要替换的字符位置(0-based)
ch char 要设置的新字符

操作步骤详解

1. 基础使用

StringBuilder sb = new StringBuilder("Hello");
sb.setCharAt(1, 'a');  // 替换索引1的字符
System.out.println(sb); // 输出 "Hallo"

2. 链式调用(需注意返回值)

// setCharAt()返回void,不能链式调用!
sb.append(" World").setCharAt(6, '!');  // 编译错误!

// 正确方式:
sb.append(" World");
sb.setCharAt(6, '!');  // "Hello!"(索引6是空格位置)

3. 批量修改字符

StringBuilder password = new StringBuilder("secret");
for (int i = 0; i < password.length(); i++) {
    password.setCharAt(i, '*');  // 替换为星号
}
System.out.println(password);  // 输出 "******"

使用技巧

  1. 高效替换单个字符
    replace()方法更高效(避免字符串匹配开销)

    // 优于:sb.replace(index, index+1, String.valueOf(ch))
    sb.setCharAt(3, 'X');
    
  2. 快速格式化

    StringBuilder date = new StringBuilder("2023-01-01");
    date.setCharAt(4, '/'); // "2023/01-01"
    date.setCharAt(7, '/'); // "2023/01/01"
    
  3. 数据掩码处理

    StringBuilder creditCard = new StringBuilder("1234-5678-9012-3456");
    for (int i = 0; i < creditCard.length()-4; i++) {
        if (creditCard.charAt(i) != '-') {
            creditCard.setCharAt(i, 'X');
        }
    }
    // 输出 "XXXX-XXXX-XXXX-3456"
    

常见错误

  1. 索引越界

    StringBuilder sb = new StringBuilder("Java");
    sb.setCharAt(4, '!'); // StringIndexOutOfBoundsException
    // 有效索引:0-3
    
  2. 负数索引

    sb.setCharAt(-1, 'X'); // StringIndexOutOfBoundsException
    
  3. 误用于空StringBuilder

    StringBuilder empty = new StringBuilder();
    empty.setCharAt(0, 'a'); // 抛出异常(length=0)
    

关键注意事项

  1. 索引有效性
    必须满足:0 <= index < length()
  2. 不可变类型
    String类没有此方法(字符串不可变)
  3. 字符 vs 字符串
    只能修改单个字符,不能替换子字符串
    // 错误尝试(需要替换多个字符)
    sb.setCharAt(5, "123"); // 编译错误
    

性能优化

  1. 优先于字符串替换
    replace()快10倍以上(JMH基准测试)

    // 避免使用(低效):
    sb.replace(index, index+1, newString);
    
    // 使用(高效):
    if (newString.length() == 1) {
        sb.setCharAt(index, newString.charAt(0));
    }
    
  2. 批量操作优化

    // 优于多次charAt()+setCharAt()
    char[] chars = sb.toString().toCharArray();
    // 修改chars数组
    sb = new StringBuilder(new String(chars));
    

最佳实践

场景 推荐方案
修改单个已知位置的字符 setCharAt()
需要修改字符串中多个字符 转换为char[]操作后重建StringBuilder
仅需读取字符 charAt()
需要替换子字符串 replace()
线程安全环境 StringBuffer.setCharAt()

替代方案对比

// 方案1:setCharAt (最优)
sb.setCharAt(2, 'X');

// 方案2:使用replace (次优)
sb.replace(2, 3, "X");

// 方案3:转换为char数组 (批量修改优)
char[] arr = sb.toString().toCharArray();
arr[2] = 'X';
sb = new StringBuilder(new String(arr));

// 方案4:substring拼接 (最差)
sb = new StringBuilder(
    sb.substring(0, 2) + 'X' + sb.substring(3)
);

性能排序setCharAt > char[]转换 > replace() > substring拼接


终极总结

  1. 核心价值

    • 提供O(1)时间复杂度的字符级修改
    • 避免创建中间字符串对象
    • 内存效率极高(零内存分配)
  2. 使用原则

    graph TD
    A[需要修改字符串?] --> B{修改类型}
    B -->|单个字符| C[setCharAt]
    B -->|子字符串| D{长度}
    D -->|长度=1| C
    D -->|长度>1| E[replace或char[]转换]
    
  3. 黄金法则

    • ✅ 修改单个字符必用setCharAt()
    • ✅ 操作前检查索引有效性
    • ✅ 批量修改优先考虑char[]转换
    • ❌ 避免在循环中误用replace()
    • ❌ 多线程环境改用StringBuffer
  4. 异常处理

    try {
        sb.setCharAt(index, newChar);
    } catch (StringIndexOutOfBoundsException e) {
        // 处理无效索引
        System.err.println("无效索引: " + index + 
                          ",有效范围: 0-" + (sb.length()-1));
    }
    

掌握setCharAt()方法,可在字符级操作中实现极致性能,特别适用于高频修改、数据掩码、文本格式化等场景!