From 04d9fbe3ca3f04262c30a04440b52f73587f5621 Mon Sep 17 00:00:00 2001 From: #fffg Date: Fri, 1 May 2026 14:49:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20StringBuffer=20=E4=B8=8E?= =?UTF-8?q?=20StringBuilder=20=E6=80=A7=E8=83=BD=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E6=AD=A7=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原文在性能部分先说明了 StringBuffer 是在原对象上进行修改(不创建新对象), 随后紧接着对比了 StringBuilder 与 StringBuffer 的性能差异。 这种表述容易让读者产生误解,将“是否创建新对象”与“性能差异”建立关联。 但实际上,StringBuffer 和 StringBuilder 都是在原对象上修改,两者的性能差异主要来源于线程安全机制 --- docs/java/basis/java-basic-questions-02.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/java/basis/java-basic-questions-02.md b/docs/java/basis/java-basic-questions-02.md index 2aa14b0946a..cb95be7eb1e 100644 --- a/docs/java/basis/java-basic-questions-02.md +++ b/docs/java/basis/java-basic-questions-02.md @@ -603,7 +603,8 @@ public native int hashCode(); **可变性** -`String` 是不可变的(后面会详细分析原因)。 +`String` 是不可变的(后面会详细分析原因),每次修改都会生成新的对象,并将引用指向新的实例,而 `StringBuffer` 和 `StringBuilder` 都是可变的,它们在修改字符串时不会创建新对象,而是直接在原有字符数组上进行操作。 + `StringBuilder` 与 `StringBuffer` 都继承自 `AbstractStringBuilder` 类,在 `AbstractStringBuilder` 中也是使用字符数组保存字符串,不过没有使用 `final` 和 `private` 关键字修饰,最关键的是这个 `AbstractStringBuilder` 类还提供了很多修改字符串的方法比如 `append` 方法。 @@ -631,7 +632,11 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { **性能** -每次对 `String` 类型进行改变的时候,都会生成一个新的 `String` 对象,然后将指针指向新的 `String` 对象。`StringBuffer` 每次都会对 `StringBuffer` 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 `StringBuilder` 相比使用 `StringBuffer` 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。 +两者的性能差异主要来源于线程安全机制: +- `StringBuffer` 的方法通常是同步的(线程安全),因此会带来一定的性能开销; +- `StringBuilder` 没有同步开销(非线程安全),在单线程场景下通常具有更好的性能表现。 +相同情况下使用 `StringBuilder` 相比使用 `StringBuffer` 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。 +另外,具体的性能差异并不是固定的,在现代 JVM 中由于锁优化(如锁消除),两者在某些场景下性能差距可能较小。 **对于三者使用的总结:**