
HoRain云小助手个人主页 个人专栏: 《Linux 系列教程》《c语言教程》⛺️生活的理想就是为了理想的生活!⛳️ 推荐前些天发现了一个超棒的服务器购买网站性价比超高大内存超划算忍不住分享一下给大家。点击跳转到网站。专栏介绍专栏名称专栏介绍《C语言》本专栏主要撰写C干货内容和编程技巧让大家从底层了解C把更多的知识由抽象到简单通俗易懂。《网络协议》本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘一起解密网络协议在运行中协议的基本运行机制《docker容器精解篇》全面深入解析 docker 容器从基础到进阶涵盖原理、操作、实践案例助您精通 docker。《linux系列》本专栏主要撰写Linux干货内容从基础到进阶知识由抽象到简单通俗易懂帮你从新手小白到扫地僧。《python 系列》本专栏着重撰写Python相关的干货内容与编程技巧助力大家从底层去认识Python将更多复杂的知识由抽象转化为简单易懂的内容。《试题库》本专栏主要是发布一些考试和练习题库涵盖软考、HCIE、HRCE、CCNA等目录⛳️ 推荐专栏介绍一、先定位三者关系二、为什么 String 拼接入坑三、StringBuffer —— JDK 1.0 老将四、StringBuilder —— JDK 1.5 轻量替代五、底层扩容机制两者相同六、一个反直觉的点a b被编译器优化了七、选型决策Java 的StringBuffer和StringBuilder都是为了解决String 不可变导致频繁拼接产生大量临时对象 这个问题而生的——两者 API 几乎一模一样核心差异就一句话StringBuffer线程安全方法加synchronizedStringBuilder非线程安全但更快。一、先定位三者关系特性StringStringBuilderStringBuffer可变性❌ 不可变final 数组✅ 可变✅ 可变线程安全✅ 天然不可变❌ 否✅ 是synchronized底层JDK 9byte[]byte[]byte[]默认容量—1616扩容规则—2n 22n 2性能拼接最差最优中等同步开销三者都实现CharSequenceStringBuilder/StringBuffer共父AbstractStringBuilder。二、为什么 String 拼接入坑// 看似一行实际背后很惨 String s ; for (int i 0; i 1000; i) { s i; // 每次 都 new 一个 StringBuilder new 一个 String }每次都会(new StringBuilder()).append(s).append(i).toString()→ 产生新 String 新 StringBuilder 新 char/byte 数组循环 1000 次就是几千个垃圾对象。三、StringBuffer —— JDK 1.0 老将StringBuffer sb new StringBuffer(32); // 建议给初始容量 sb.append(Hello).append( ).append(World); sb.insert(5, ,); // Hello, World sb.reverse(); // dlroW ,olleH String result sb.toString();关键点所有append/insert/delete/replace都加synchronized多线程共享一个 buffer 不会乱但注意synchronized只锁当前 StringBuffer 对象本身如果构造/append 时传入的源序列是线程间共享的可变对象调用方自己还得保证源序列不变JDK 1.0 就有历史包袱重单线程场景下 synchronized 纯浪费四、StringBuilder —— JDK 1.5 轻量替代API 和 StringBuffer完全一样只是把synchronized全去掉了StringBuilder sb new StringBuilder(256); // 预分配减少扩容 sb.append(SELECT * FROM user WHERE 11); if (name ! null) { sb.append( AND name LIKE %).append(name).append(%); }单线程下比 StringBuffer 快 10%~20%高并发循环差距更明显。五、底层扩容机制两者相同// AbstractStringBuilder 里的逻辑 int newCapacity (oldCapacity 1) 2; // 2n 2默认容量16追加后count 新增长度 value.length→ 触发扩容拷数组O(n) 成本所以如果能预估大小构造函数里给容量是高性价比优化// 知道大概要拼 200 字符直接给避免中途扩容 new StringBuilder(256);六、一个反直觉的点a b被编译器优化了// 源码 String s a b c; // javac 编译后等价于 String s new StringBuilder().append(a).append(b).append(c).toString();所以方法体内偶尔拼几下用没问题编译器已经帮你换了StringBuilder。但循环里用就炸——每次循环都会 new 一个 StringBuilder等于没优化。// ❌ 循环内 号每次 new StringBuilder for (...) { s i; } // ✅ 手动提外面 StringBuilder sb new StringBuilder(); for (...) { sb.append(i); }七、选型决策单线程 / 方法局部变量 →StringBuilder默认首选多线程共享同一个 buffer →StringBuffer或更现代的做法ThreadLocalStringBuilder/ 外部加锁不修改 → 直接用String实际开发现状Spring / Jackson / MyBatis / Log4j2 这类框架内部几乎全是StringBuilder因为大多在方法栈内用完即扔天然线程安全栈封闭StringBuffer在现代代码里越来越少见主要是 legacy 系统还在用JDK 文档自己也推荐优先StringBuilder要不要接着看String的intern()和字符串常量池那块这俩经常和 StringBuilder 一起考比如new String(a) new String(b)到底进不进池、什么时候成立。❤️❤️❤️本人水平有限如有纰漏欢迎各位大佬评论批评指正如果觉得这篇文对你有帮助的话也请给个点赞、收藏下吧非常感谢! Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧