Java中String、StringBuffer和StringBuilder底层实现深入剖析

 更新时间:2026年01月08日 10:22:03   作者:Ricky_Ribbon  
在Java编程语言中String、StringBuffer和StringBuilder都是用来处理字符串的类,但它们之间存在显著的性能和功能差异,这篇文章主要介绍了Java中String、StringBuffer和StringBuilder底层实现的相关资料,需要的朋友可以参考下

前言

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

1. 全面对比表

比较维度StringStringBufferStringBuilder
可变性不可变(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.0JDK 1.0JDK 1.5(为单线程优化而新增)
继承关系继承 AbstractStringBuilder,实现 CharSequence、Serializable、Comparable继承 AbstractStringBuilder,实现 Appendable 等继承 AbstractStringBuilder,实现 Appendable 等
方法同步无需同步大部分修改方法(如 append、delete)都是 synchronized无 synchronized
典型使用场景常量字符串、键值存储、配置信息多线程频繁拼接(如日志记录、共享缓冲)单线程频繁拼接(如 JSON 构建、循环拼接)——现代项目首选
toString() 实现返回自身(缓存优化 JDK 7+)新建 String 对象(调用 Arrays.copyOf)同 StringBuffer

2. 底层实现深入剖析

  • String 的不可变性

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

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

  • StringBuffer / StringBuilder 的可变性
    两者都继承自 AbstractStringBuilder

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

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

    // StringBuffer 示例
    public synchronized StringBuffer append(String str) { ... }
    
    // StringBuilder 示例
    public StringBuilder append(String str) { ... }  // 无 synchronized
    

3. 性能对比实测(循环 10 万次拼接)

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:

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

5. 选择指南(实战总结)

  1. 内容几乎不修改 → 用 String(最安全、支持常量池)。

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

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

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

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

6. 常见误区澄清

  • 误区:StringBuffer 完全过时了 → 错!在多线程共享同一缓冲时仍有价值。
  • 误区:StringBuilder 线程不安全就不能用 → 大多数业务是单线程,安全使用即可。
  • 误区:String 完全不能用于拼接 → 小量拼接没问题,大量必须避免。

总结

到此这篇关于Java中String、StringBuffer和StringBuilder底层实现的文章就介绍到这了,更多相关Java中String、StringBuffer和StringBuilder内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA和JAVAC 命令详细介绍

    JAVA和JAVAC 命令详细介绍

    这篇文章主要介绍了JAVA和JAVAC 命令详细介绍的相关资料,本文对java 和javac 命令进行了详解,并在Windows和Linux 平台分别说明,需要的朋友可以参考下
    2016-11-11
  • Java设置session超时的几种方式总结

    Java设置session超时的几种方式总结

    这篇文章主要介绍了Java设置session超时的几种方式总结的相关资料,需要的朋友可以参考下
    2017-07-07
  • Spring Boot Event Bus用法小结

    Spring Boot Event Bus用法小结

    Spring Boot Event Bus是Spring框架中事件驱动编程的一部分,本文主要介绍了Spring Boot Event Bus用法小结,感兴趣的可以了解一下
    2023-09-09
  • IDEA如何将Java项目打包成可执行的Jar包

    IDEA如何将Java项目打包成可执行的Jar包

    在Java开发中,我们通常会将我们的项目打包成可执行的Jar包,以便于在其他环境中部署和运行,本文将介绍如何使用IDEA集成开发环境将Java项目打包成可执行的Jar包,感兴趣的朋友一起看看吧
    2023-07-07
  • Java程序图形用户界面设计之标签组件

    Java程序图形用户界面设计之标签组件

    图形界面(简称GUI)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受,本篇精讲Java语言中关于图形用户界面的标签组件部分
    2022-02-02
  • 全解史上最快的JOSN解析库alibaba Fastjson

    全解史上最快的JOSN解析库alibaba Fastjson

    这篇文章主要介绍了史上最快的JOSN解析库alibaba Fastjson,对FastJson感兴趣的同学,一定要看一下
    2021-04-04
  • Feign如何使用protobuf的类作为参数调用

    Feign如何使用protobuf的类作为参数调用

    这篇文章主要介绍了Feign如何使用protobuf的类作为参数调用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • SpringBoot项目创建单元测试的流程步骤

    SpringBoot项目创建单元测试的流程步骤

    在日常开发的过程中,对自己的代码进行单元测试是个非常重要的过程,一方面可以最小范围的针对一个方法进行测试,提高测试的简便性以及测试的成本,本篇文章主要是为了总结一下如何优雅的在Springboot项目中使用单元测试去测试功能,需要的朋友可以参考下
    2024-11-11
  • 使用java实现http多线程断点下载文件(一)

    使用java实现http多线程断点下载文件(一)

    Java 多线程断点下载文件基本原理:利用URLConnection获取要下载文件的长度、头部等相关信息,并设置响应的头部信息,本文将详细介绍,需要了解更多的朋友可以参考下
    2012-12-12
  • Spring Data Jpa 中原生查询 REGEXP 的使用详解

    Spring Data Jpa 中原生查询 REGEXP 的使用详解

    这篇文章主要介绍了Spring Data Jpa 中原生查询 REGEXP 的使用详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论