• 你知道JAVA中String、StringBuffer和StringBuilder三者间的本质区别吗?
  • 发布于 1周前
  • 106 热度
    0 评论
  • 顾及谁
  • 24 粉丝 46 篇博客
  •   
Java中的String、StringBuffer和StringBuilder是高频面试题,但很多程序员只停留在“线程安全”的浅层理解。它们的设计哲学、性能差异、底层实现才是技术深度的体现! 今天用最直白的语言,带你彻底搞懂这三者的本质区别!
一、不可变性:String的“铁律”与StringBuffer/StringBuilder的“灵活”
String:一旦创建,永不改变
• 底层实现:private final byte[] value(JDK9后改用byte数组)
• 任何修改操作(如拼接、替换)都会生成新对象,旧对象留在内存中等待GC回收。
• 优点:线程安全、支持字符串常量池缓存。
• 缺点:频繁修改时内存浪费严重,性能低下。
String s = "Hello";
s += " World";  // 实际生成新对象"Hello World",原对象仍在内存中
StringBuffer & StringBuilder:可变字符序列
• 底层实现:char[] value(JDK8及以前),无final修饰,支持动态扩容。
• 修改操作直接修改原对象,无需生成新对象,内存利用率高。

二、线程安全:StringBuffer的“锁”与StringBuilder的“自由”
1.StringBuffer:同步方法保证安全
• 所有公共方法加synchronized锁,多线程操作时数据一致。
• 代价:频繁加锁导致性能损耗(单线程效率比StringBuilder低约10%~15%)。
2.StringBuilder:为性能放弃安全
• 无锁设计,单线程下性能最优,但多线程操作可能数据错乱。
• 适用场景:日志拼接、SQL动态生成等单线程高频操作。
3.String的“伪线程安全”
• 不可变性天然线程安全,但需注意共享变量被多线程指向不同对象的问题。
三、性能对比:从底层看效率差距
1.字符串拼接实验
// String拼接:每次循环生成新对象,性能最差
String s = "";
for (int i =0; i<10000; i++) s += i;  // 触发编译器优化为StringBuilder,但循环内仍反复创建对象
// 堆代码 duidaima.com
// StringBuilder:单线程性能王者
StringBuilder sb = new StringBuilder();
for (int i=0; i<10000; i++) sb.append(i);  // 直接操作char数组,无锁
// StringBuffer:安全但低效
StringBuffer sbf = new StringBuffer();
for (int i=0; i<10000; i++) sbf.append(i);  // 每次append加锁
耗时排序:StringBuilder < StringBuffer < String(差距可达百倍!)
2.扩容机制
• 初始容量:默认16,扩容公式为旧容量*2 +2。
• 优化建议:预估数据量,初始化时指定容量避免频繁扩容。
四、使用场景:选对类,性能翻倍
场景 推荐类 理由
字符串常量、少量拼接 String 利用常量池缓存,代码简洁
单线程高频操作(如循环) StringBuilder 无锁,性能碾压其他类
多线程共享变量 StringBuffer 同步方法保证安全,但需容忍性能损失
数据库SQL动态拼接 StringBuilder 单线程且需高效

五、高频面试题解析

1.为什么String不可变?
• 安全:防止黑客通过反射修改值;
• 性能:支持常量池缓存、哈希计算优化。
2.StringBuilder和StringBuffer的父类是什么?
• 均继承AbstractStringBuilder,共享扩容、插入等核心逻辑。
3.String拼接的底层原理?

• 编译器将+优化为StringBuilder,但循环内反复创建对象导致性能问题。

总结
• String:适合静态数据,利用常量池减少内存开销。
• StringBuilder:单线程性能之王,无锁设计碾压对手。
• StringBuffer:多线程环境保底选择,用性能换安全。
用户评论