当前位置: 首页 > news >正文

String、StringBuffer 和 StringBuilder 的区别

目录

1. 概述对比

2. String:不可变的字符串

2.1 基本特性

2.2 使用示例

2.3 适用场景

3. StringBuffer:可变的线程安全字符串

3.1 基本特性

3.2 使用示例

3.3 适用场景

4. StringBuilder:可变的非线程安全字符串

4.1 基本特性

4.2 使用示例

4.3 适用场景

5. 性能对比

5.1 性能测试代码

5.2 测试结果

6. 内存使用对比

6.1 String 的内存使用

6.2 StringBuffer/StringBuilder 的内存使用

7. 最佳实践

7.1 选择原则

7.2 代码示例

7.3 初始化容量优化

8. 总结


在 Java 开发中,字符串处理是最常见的操作之一。Java 提供了三种主要的字符串类:String、StringBuffer 和 StringBuilder。理解它们之间的区别对于编写高效、正确的代码至关重要。

1. 概述对比

特性

String

StringBuffer

StringBuilder

可变性

不可变

可变

可变

线程安全

是(天生线程安全)

是(同步方法)

否(非线程安全)

性能

最低(频繁创建新对象)

中等(有同步开销)

最高(无同步开销)

使用场景

字符串常量、少量操作

多线程环境下的字符串操作

单线程环境下的字符串操作

内存效率

低(频繁操作时)

最高

版本引入

Java 1.0

Java 1.0

Java 5

2. String:不可变的字符串

2.1 基本特性

String 是不可变类,一旦创建就不能修改。任何看似修改 String 的操作实际上都是创建了一个新的 String 对象。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {private final char value[]; // Java 8 及之前private final byte[] value; // Java 9 及之后// ...
}

2.2 使用示例

// 创建字符串
String str1 = "Hello"; // 字面量方式,放入字符串常量池
String str2 = new String("Hello"); // 创建新对象// 字符串操作(都返回新对象)
String result = str1.concat(" World"); // 拼接
String upper = result.toUpperCase();   // 转大写
String sub = result.substring(6);      // 子字符串System.out.println(str1); // 输出: Hello(原字符串未改变)
System.out.println(result); // 输出: Hello World

2.3 适用场景

  • 字符串常量定义
  • 不需要频繁修改的字符串
  • 作为 HashMap 的键(利用不可变性)
  • 多线程环境下的字符串共享

3. StringBuffer:可变的线程安全字符串

3.1 基本特性

StringBuffer 是可变的字符序列,所有修改方法都使用 synchronized 关键字保证线程安全。

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence {@Overridepublic synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;}// 其他方法也都是同步的
}

3.2 使用示例

StringBuffer sb = new StringBuffer("Hello");// 链式操作,直接修改原对象
sb.append(" ").append("World").append("!").insert(5, " Beautiful");System.out.println(sb.toString()); // 输出: Hello Beautiful World!// 线程安全示例
StringBuffer threadSafeBuffer = new StringBuffer();
Runnable task = () -> {for (int i = 0; i < 1000; i++) {threadSafeBuffer.append(i).append(" ");}
};// 多个线程同时操作是安全的
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();

3.3 适用场景

  • 多线程环境下的字符串操作
  • 需要线程安全的字符串构建
  • 复杂的字符串拼接和修改

4. StringBuilder:可变的非线程安全字符串

4.1 基本特性

StringBuilder 与 StringBuffer API 几乎完全相同,但方法没有同步,因此性能更高。

public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {@Overridepublic StringBuilder append(String str) {super.append(str);return this;}// 方法没有 synchronized 关键字
}

4.2 使用示例

StringBuilder sb = new StringBuilder("Hello");// 高效的链式操作
sb.append(" ").append("World").append("!").insert(5, " Amazing");System.out.println(sb.toString()); // 输出: Hello Amazing World!// 单线程环境下性能最佳
long startTime = System.currentTimeMillis();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100000; i++) {builder.append(i);
}
long endTime = System.currentTimeMillis();
System.out.println("StringBuilder 耗时: " + (endTime - startTime) + "ms");

4.3 适用场景

  • 单线程环境下的字符串操作
  • 性能要求高的字符串处理
  • 大量的字符串拼接和修改

5. 性能对比

5.1 性能测试代码

public class StringPerformanceTest {private static final int ITERATIONS = 100000;public static void testString() {long start = System.currentTimeMillis();String str = "";for (int i = 0; i < ITERATIONS; i++) {str += i; // 每次循环创建新对象}long end = System.currentTimeMillis();System.out.println("String 耗时: " + (end - start) + "ms");}public static void testStringBuffer() {long start = System.currentTimeMillis();StringBuffer sb = new StringBuffer();for (int i = 0; i < ITERATIONS; i++) {sb.append(i);}long end = System.currentTimeMillis();System.out.println("StringBuffer 耗时: " + (end - start) + "ms");}public static void testStringBuilder() {long start = System.currentTimeMillis();StringBuilder sb = new StringBuilder();for (int i = 0; i < ITERATIONS; i++) {sb.append(i);}long end = System.currentTimeMillis();System.out.println("StringBuilder 耗时: " + (end - start) + "ms");}public static void main(String[] args) {testString();testStringBuffer();testStringBuilder();}
}

5.2 测试结果

String 耗时: 4235ms
StringBuffer 耗时: 8ms
StringBuilder 耗时: 5ms

6. 内存使用对比

6.1 String 的内存使用

String result = "";
for (int i = 0; i < 10; i++) {result += i; // 创建11个String对象
}
// 产生大量垃圾对象,增加GC压力

6.2 StringBuffer/StringBuilder 的内存使用

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {sb.append(i); // 在同一个缓冲区中操作
}
// 只在需要时扩容,内存使用高效

7. 最佳实践

7.1 选择原则

1.使用 String

  • 字符串常量
  • 不需要修改的字符串
  • 多线程共享的字符串

2.使用 StringBuffer

  • 多线程环境下的字符串操作
  • 需要线程安全的字符串构建

3.使用 StringBuilder

  • 单线程环境下的字符串操作
  • 性能要求高的场景
  • 方法内部的字符串处理

7.2 代码示例

public class StringBestPractices {// 常量使用 Stringpublic static final String DATABASE_URL = "jdbc:mysql://localhost:3306/mydb";// 方法参数使用 String(不可变,安全)public void processMessage(String message) {// 处理消息}// 单线程字符串构建使用 StringBuilderpublic String buildQuery(List<String> conditions) {StringBuilder query = new StringBuilder("SELECT * FROM users WHERE 1=1");for (String condition : conditions) {query.append(" AND ").append(condition);}return query.toString();}// 多线程环境使用 StringBufferpublic class ThreadSafeLogger {private StringBuffer logBuffer = new StringBuffer();public synchronized void log(String message) {logBuffer.append(new Date()).append(": ").append(message).append("\n");}public String getLog() {return logBuffer.toString();}}
}

7.3 初始化容量优化

// 如果知道大致长度,可以预先设置容量
StringBuilder sb = new StringBuilder(1000); // 预分配容量
for (int i = 0; i < 1000; i++) {sb.append("item").append(i).append(",");
}
// 避免多次扩容,提高性能

8. 总结

方面

String

StringBuffer

StringBuilder

核心特点

不可变

可变、线程安全

可变、非线程安全

性能排序

最慢

中等

最快

线程安全

内存效率

低(频繁操作时)

最高

使用场景

常量、少量操作

多线程字符串操作

单线程字符串操作

黄金法则

  • 如果字符串不需要改变:使用 String
  • 如果在单线程中需要改变字符串:使用 StringBuilder
  • 如果在多线程中需要改变字符串:使用 StringBuffer

希望本篇文章对你有帮助。


文章转载自:

http://eiYkWmmJ.jmtrq.cn
http://oxBSrql1.jmtrq.cn
http://WJh6fMSU.jmtrq.cn
http://ogpXO73x.jmtrq.cn
http://us1UwXac.jmtrq.cn
http://IbiPO53Y.jmtrq.cn
http://bvE00HHy.jmtrq.cn
http://Xc2jgAZa.jmtrq.cn
http://fwOwAYya.jmtrq.cn
http://pMiECWjf.jmtrq.cn
http://fiOZSTc7.jmtrq.cn
http://lPIFcL4z.jmtrq.cn
http://zV3Z5yte.jmtrq.cn
http://y6BwJpZZ.jmtrq.cn
http://pOjF1zpw.jmtrq.cn
http://AwazxKgJ.jmtrq.cn
http://l8hghSD8.jmtrq.cn
http://hzbIGs0f.jmtrq.cn
http://FKrkKgYr.jmtrq.cn
http://n7vO0ZG3.jmtrq.cn
http://gCYIXQMB.jmtrq.cn
http://8lB0nrdX.jmtrq.cn
http://aIj054WC.jmtrq.cn
http://LXpjQuC0.jmtrq.cn
http://CcdKUsfd.jmtrq.cn
http://mt2KaZXs.jmtrq.cn
http://9gciy3iU.jmtrq.cn
http://LaODN6Mv.jmtrq.cn
http://QwT29Mpc.jmtrq.cn
http://dF5LoM5L.jmtrq.cn
http://www.dtcms.com/a/382615.html

相关文章:

  • 测试抽奖系统,设计测试case
  • vue的响应式原理深度解读
  • Python核心技术开发指南(061)——常用魔术方法
  • 简单概述操作系统的发展
  • 从0开始:STM32F103C8T6开发环境搭建与第一个LED闪烁
  • linux C 语言开发 (九) 进程间通讯--管道
  • LinuxC++项目开发日志——高并发内存池(5-page cache框架开发)
  • MATLAB基于组合近似模型和IPSO-GA的全焊接球阀焊接工艺参数优化研究
  • SpringSecurity的应用
  • 算法题(206):方格取数(动态规划)
  • 第十六周周报
  • [硬件电路-193]:双极型晶体管BJT与场效应晶体管FET异同
  • ID3v2的header中的扩展标头(Extended Header),其Size字段如何计算整个ID3的长度?
  • 【51单片机】【protues仿真】基于51单片机的篮球计时计分器系统
  • Linux -- 权限的理解
  • Java零基础学习Day10——面向对象高级1
  • 解析通过base64 传过来的图片
  • Redis 持久化策略
  • STM32---PWR
  • 0913刷题日记
  • Java基础面试篇(7)
  • 4-机器学习与大模型开发数学教程-第0章 预备知识-0-4 复数与指数形式(欧拉公式)
  • TA-VLA——将关节力矩反馈融入VLA中:无需外部力传感器,即可完成汽车充电器插入(且可多次自主尝试)
  • 从0到1开发一个商用 Agent(智能体),Agent零基础入门到精通!_零基础开发aiagent 用dify从0到1做智能体
  • android 消息队列MessageQueue源码阅读
  • Gtest2025大会学习记录(全球软件测试技术峰会)
  • oneshape acad数据集 sam-dataset
  • 堆(优先队列)
  • 【卷积神经网络详解与实例】7——经典CNN之AlexNet
  • Digital Clock 4,一款免费的个性化桌面数字时钟