Java 中 String、StringBuffer 和 StringBuilder

Java 中 StringStringBufferStringBuilder

这三个类都是 java.lang 包下的字符串处理类,但它们在设计理念、内部实现和适用场景上存在显著差异。

1. 全面对比表
比较维度 String StringBuffer StringBuilder
可变性 不可变(Immutable) 内容一旦创建无法修改 可变(Mutable) 支持原地修改 可变(Mutable) 支持原地修改
线程安全 天然线程安全(不可变对象) 线程安全 关键方法(如 append、insert)加了 synchronized 非线程安全 无任何同步机制
性能 修改操作最慢(频繁创建新对象) 中等(有锁开销,但比 String 好) 最高(无锁,单线程下最优)
内部存储 底层是 final char[] value(JDK 7+) JDK 8 前是 char[],不可扩容 底层是 char[] value,可动态扩容 底层是 char[] value,可动态扩容(实现几乎相同)
容量扩容机制 无(固定长度) 默认容量 16,扩容时新容量 = (旧容量 * 2) + 2 同 StringBuffer:默认 16,扩容时新容量 = (旧容量 * 2) + 2
内存占用 每次修改产生新对象 + 新 char[],GC 压力大 共享同一 char[],内存高效 同 StringBuffer,内存高效
字符串常量池 支持常量池缓存(字面量可复用) 不支持常量池 不支持常量池
引入版本 JDK 1.0 JDK 1.0 JDK 1.5(为单线程优化而新增)
继承关系 继承 AbstractStringBuilder,实现 CharSequence、Serializable、Comparable 继承 AbstractStringBuilder,实现 Appendable 等 继承 AbstractStringBuilder,实现 Appendable 等
方法同步 无需同步 大部分修改方法(如 append、delete)都是 synchronized 无 synchronized
典型使用场景 常量字符串、键值存储、配置信息 多线程频繁拼接(如日志记录、共享缓冲) 单线程频繁拼接(如 JSON 构建、循环拼接)------现代项目首选
toString() 实现 返回自身(缓存优化 JDK 7+) 新建 String 对象(调用 Arrays.copyOf) 同 StringBuffer
2. 底层实现深入剖析
  • String 的不可变性

    java 复制代码
    // JDK 源码简化版
    public final class String {
        private final char[] value;  // final 修饰,不可重新赋值
        private final int hash;      // 缓存 hashCode
    }

    任何"修改"操作(如 concatreplace)都会 new String() 并复制 char[],原对象不变。

  • StringBuffer / StringBuilder 的可变性

    两者都继承自 AbstractStringBuilder

    java 复制代码
    abstract class AbstractStringBuilder {
        char[] value;      // 非 final,可扩容
        int count;         // 当前长度
    }
    • append 等操作直接操作 value 数组。
    • 扩容时:Arrays.copyOf 创建更大数组,复制旧内容。

    关键区别 :StringBuffer 的公共方法加了 synchronized

    java 复制代码
    // StringBuffer 示例
    public synchronized StringBuffer append(String str) { ... }
    
    // StringBuilder 示例
    public StringBuilder append(String str) { ... }  // 无 synchronized
3. 性能对比实测(循环 10 万次拼接)
java 复制代码
public class Test {
    public static void main(String[] args) {
        int times = 100000;

        // String
        long start = System.nanoTime();
        String s = "";
        for (int i = 0; i < times; i++) {
            s += i;
        }
        System.out.println("String 用时: " + (System.nanoTime() - start) / 1e6 + " ms");

        // StringBuilder
        start = System.nanoTime();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < times; i++) {
            sb.append(i);
        }
        System.out.println("StringBuilder 用时: " + (System.nanoTime() - start) / 1e6 + " ms");

        // StringBuffer
        start = System.nanoTime();
        StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < times; i++) {
            sbf.append(i);
        }
        System.out.println("StringBuffer 用时: " + (System.nanoTime() - start) / 1e6 + " ms");
    }
}

典型运行结果(JDK 17,普通电脑):

  • String:约 3000~5000 ms(极慢,产生海量临时对象)
  • StringBuilder:约 10~20 ms
  • StringBuffer:约 15~30 ms(略慢于 Builder,因锁开销)

可见,频繁修改时 StringBuilder 性能遥遥领先。

4. 编译器优化小秘密
  • 单次 + 操作:JVM 会自动优化为 StringBuilder:

    java 复制代码
    String result = "a" + "b" + "c";  // 编译后相当于 new StringBuilder().append("a").append("b").append("c").toString()
  • 循环中 + 操作:不会跨循环优化,仍建议手动用 StringBuilder。

5. 选择指南(实战总结)
  1. 内容几乎不修改 → 用 String(最安全、支持常量池)。

  2. 多线程 + 频繁修改 → 用 StringBuffer(虽慢点但安全)。

  3. 单线程 + 频繁修改必须用 StringBuilder(性能最佳,99% 场景适用)。

  4. 已知长度大 → 提前指定容量,避免扩容:

    java 复制代码
    StringBuilder sb = new StringBuilder(10000);  // 预分配
  5. 现代替代方案 :复杂场景可考虑 String.join()String.format() 或流式操作,但核心拼接仍推荐 StringBuilder。

6. 常见误区澄清
  • 误区:StringBuffer 完全过时了 → 错!在多线程共享同一缓冲时仍有价值。
  • 误区:StringBuilder 线程不安全就不能用 → 大多数业务是单线程,安全使用即可。
  • 误区:String 完全不能用于拼接 → 小量拼接没问题,大量必须避免。
相关推荐
ss2732 小时前
类的线程安全:多线程编程-银行转账系统:如果两个线程同时修改同一个账户余额,没有适当的保护机制,会发生什么?
java·开发语言·数据库
写代码的【黑咖啡】2 小时前
深入了解 Python 中的 Seaborn:优雅的数据可视化利器
开发语言·python·信息可视化
星火开发设计2 小时前
栈的深度解析与C++实现
开发语言·数据结构·c++·学习·知识
再睡一夏就好2 小时前
LInux线程池实战:单例模式设计与多线程安全解析
linux·运维·服务器·开发语言·javascript·c++·ecmascript
一只叫煤球的猫2 小时前
并行不等于更快:CompletableFuture 让你更慢的 5 个姿势
java·后端·性能优化
莓有烦恼吖2 小时前
基于AI图像识别与智能推荐的校园食堂评价系统研究 04-评价系统模块
java·tomcat·web·visual studio
郝学胜-神的一滴2 小时前
机器学习数据工程之基石:论数据集划分之道与sklearn实践
开发语言·人工智能·python·程序人生·机器学习·sklearn
Wpa.wk2 小时前
接口自动化 - 了解接口自动化框架RESTAssured (Java版)
java·数据库·自动化
沐知全栈开发2 小时前
MySQL 分组
开发语言