String vs StringBuilder vs StringBuffer深度解析

Java 面试核心:String vs StringBuilder vs StringBuffer 深度解析

一、三者核心区别一览

特性 String StringBuilder StringBuffer
可变性 不可变 (Immutable) 可变 (Mutable) 可变 (Mutable)
线程安全 安全(但无关,因为不可变) 不安全 安全(synchronized)
性能 低(每次操作创建新对象) (单线程最快) 中(同步带来开销)
使用场景 字符串常量、少量操作 单线程大量字符串拼接 多线程大量字符串拼接
JDK版本 1.0 1.5 1.0

二、String 的不可变性(Immutable)

为什么不可变?

java 复制代码
// 典型面试代码
String s = "hello";
s = s + " world";  // 创建了新对象,s指向新引用,"hello"被GC

不可变的好处:

  1. 字符串常量池复用 --- 节省内存
  2. HashCode 缓存 --- 适合作为 HashMap 的 Key
  3. 线程安全 --- 天然并发安全
  4. 安全 --- 防止参数被篡改(如网络传输、文件路径)

经典面试题

Q:以下代码创建了几个对象?

java 复制代码
String s1 = new String("abc");

A:2个 --- 堆中的 new String() 对象 + 常量池中的 "abc"
Q:String.intern() 的作用?
A: 将字符串放入常量池,返回常量池引用。用于手动控制字符串复用。


三、StringBuilder vs StringBuffer 源码级对比

1. 线程安全差异(核心考点)

java 复制代码
// StringBuffer:方法加 synchronized
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

// StringBuilder:无同步,裸奔
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

2. 扩容机制(两者相同)

java 复制代码
// 默认初始容量 16,扩容:新容量 = 旧容量 × 2 + 2
void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    // ...
}

面试建议: 预估长度时用 new StringBuilder(100) 避免频繁扩容。


四、性能对比实测

操作 耗时 说明
String + 循环10000次 很慢 创建大量临时对象
StringBuilder 单线程 最快 无锁,直接操作字符数组
StringBuffer 单线程 较慢 同步锁开销
StringBuffer 多线程 安全 正确性优先

结论: 单线程无脑用 StringBuilder,多线程才考虑 StringBuffer


五、高频面试题精编

Q1:为什么 String 设计成不可变的?

答: 安全(防篡改)、高效(常量池复用)、线程安全、HashCode 缓存。

Q2:+ 操作符底层用什么?

答: JDK8+ 编译器自动转为 StringBuilder.append(),但循环中会每次新建 Builder,应手动用 Builder。

Q3:StringBuilder 为什么快?

答: 1)可变字符数组,原地修改;2)无同步锁开销;3)扩容时批量复制。

Q4:什么场景必须用 StringBuffer?

答: 多线程并发修改同一字符串对象时(实际很少见,通常用并发容器或局部变量)。


六、最佳实践速记

场景 推荐选择
字符串常量、配置项 String
单线程字符串拼接(循环、流处理) StringBuilder
多线程共享可变字符串(罕见) StringBuffer
高并发日志、序列化 StringBuilder(局部变量)

七、总结

String 是不可变的常量,StringBuilder 是单线程的快刀,StringBuffer 是多线程的保险柜。现代 Java 开发,90% 场景用 StringBuilder,剩下 9% 用 String,1% 才用 StringBuffer。


相关推荐
EXI-小洲7 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
2601_961901708 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring
何以解忧,唯有..8 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
QQ_21696290969 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端
前端 贾公子10 小时前
第09章:上下文与记忆 (2)
java·服务器·前端
2601_9622035110 小时前
Java进阶07集合(续)
java·开发语言
郑州光合科技余经理10 小时前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
roman_日积跬步-终至千里11 小时前
【数据治理(6)】DataOps 不是调度工具,而是让数据产品长期可信的运行机制
java·服务器·网络
落魄大学生之流水线上谋生计11 小时前
LangGraph 基本用法指南
java·windows·python·langchain
2601_9621284111 小时前
SpringBoot篇(缓存层)
java·spring boot·缓存