3.String、StringBuilder、StringBuffer:性能差别多大?

String三兄弟性能对比

String、StringBuilder、StringBuffer:性能差别多大?

🚀 高频指数:★★★★★
🎯 你将收获:字符串常量池机制、不可变性的原理、三者底层结构与性能对比、项目实战场景。


一、面试常见问法

💬 面试官:

  1. String 为什么是不可变的?
  2. StringBuilder 和 StringBuffer 区别?
  3. 你会在什么场景下使用它们?

答不好这几句,面试官马上能看出你是否真正理解 Java 内存模型与线程安全。


二、String 的不可变性

🔹 源码结构(JDK 8)

public final class String implements java.io.Serializable, Comparable<String> {
    private final char value[];
}
  • final 修饰类 → 不可继承;
  • value[]final → 字符数组地址不可变;
  • 内部方法不会改变原数组,而是生成新对象。

🔹 设计目的

  1. 安全性:字符串常用于类加载、反射、HashMap key;
  2. 线程安全:不可变对象天然线程安全;
  3. 缓存优化:可放入字符串常量池重复利用。

☕️ 一句话记忆:“安全、共享、缓存”造就不可变性。


三、字符串常量池机制(String Constant Pool)

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
  • 常量 "hello" 存放于 字符串常量池(JDK7 以前在永久代,JDK8 移至堆)。
  • 相同字面量只存一份,节省内存。

🔹 注意点:new String()

String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2); // false
  • "abc" 是常量池对象;
  • new String() 在堆中新建一个副本。

四、StringBuilder 与 StringBuffer

对比项StringStringBuilderStringBuffer
可变性不可变可变可变
线程安全安全(因不可变)❌ 不安全✅ 安全(同步)
性能低(频繁创建新对象)略低于 StringBuilder
关键修饰final无同步synchronized
适用场景少量字符串单线程大量拼接多线程拼接

🔹 核心源码片段

// StringBuilder.append()
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

// AbstractStringBuilder
public AbstractStringBuilder append(String str) {
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

内部维护 char[] value,通过扩容策略动态拼接。

StringBuffer 在方法上加了 synchronized,因此多线程安全,但性能稍慢。


五、性能测试(简化示例)

public static void main(String[] args) {
    long start, end;

    start = System.currentTimeMillis();
    String s = "";
    for (int i = 0; i < 50000; i++) {
        s += i;
    }
    end = System.currentTimeMillis();
    System.out.println("String: " + (end - start));

    start = System.currentTimeMillis();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 50000; i++) {
        sb.append(i);
    }
    end = System.currentTimeMillis();
    System.out.println("StringBuilder: " + (end - start));

    start = System.currentTimeMillis();
    StringBuffer sbf = new StringBuffer();
    for (int i = 0; i < 50000; i++) {
        sbf.append(i);
    }
    end = System.currentTimeMillis();
    System.out.println("StringBuffer: " + (end - start));
}

输出结果(不同机器略有差异):

String: 1800 ms
StringBuilder: 12 ms
StringBuffer: 20 ms

⚡️ 结论:频繁拼接字符串时,StringBuilder 性能优势极大。


六、面试官追问清单

问题答题要点
为什么 String 是不可变的?因为 value[] 被 final 修饰,引用不可变。
StringBuilder 与 StringBuffer 区别?前者非线程安全、性能更高;后者加了同步锁。
StringBuilder 线程安全吗?否,不能在多线程共享。
常量池位置在哪?JDK8 之后在堆中。
String + 拼接为什么慢?每次 + 都创建新对象。

七、口诀记忆

☕️ “String 稳,Builder 快,Buffer 稳又慢。”

补充版:
“常量池省空间,final 保安全;单线程用 Builder,多线程用 Buffer。”


八、项目实战案例

场景:日志拼接、SQL 动态生成、报文组装。

StringBuilder sql = new StringBuilder("SELECT * FROM user WHERE 1=1");
if (age != null) sql.append(" AND age=").append(age);
if (name != null) sql.append(" AND name='").append(name).append("'");

若使用 String 拼接,会频繁创建对象;
若多线程同时组装日志,应使用 StringBuffer 或加锁。


九、小结

知识点要点
String 不可变内部 final char[]
常量池优化相同字面量复用
StringBuilder 可变高性能单线程使用
StringBuffer 加锁安全多线程拼接

✅ 口诀复盘:“单线快,双线锁,字符串常量池共享。”

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愤怒的代码

如果您有受益,欢迎打赏博主😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值