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 完全不能用于拼接 → 小量拼接没问题,大量必须避免。
相关推荐
fie888913 小时前
基于MATLAB的时变Copula实现方案
开发语言·matlab
冬奇Lab13 小时前
【Kotlin系列12】函数式编程在Kotlin中的实践:从Lambda到函数组合的优雅之旅
android·开发语言·kotlin
消失的旧时光-194313 小时前
第六课 · 6.1 从 JDBC 到 MyBatis:SQL 工程化是如何发生的?
java·sql·mybatis
写代码的【黑咖啡】13 小时前
Python中的Msgpack:高效二进制序列化库
开发语言·python
Jaxson Lin13 小时前
Java编程进阶:线程基础与实现方式全解析
java·开发语言
夜喵YM13 小时前
基于 Spire.XLS.Free for Java 实现无水印 Excel 转 PDF
java·pdf·excel
xiaoqider14 小时前
C++继承
开发语言·c++
茶本无香14 小时前
设计模式之五—门面模式:简化复杂系统的统一接口
java·设计模式
阿华hhh14 小时前
day4(IMX6ULL)<定时器>
c语言·开发语言·单片机·嵌入式硬件
她说可以呀14 小时前
网络基础初识
java·网络·java-ee