深入理解String、StringBuffer和StringBuilder类的区别

深入理解String、StringBuffer和StringBuilder类的区别

https://blog.meowrain.cn/api/i/2025/07/04/zmif5z-1.webp

String类

String类是一个不可变类,即创建String对象后,该对象中的字符串是不可改变的,直到这个对象被销毁。存储在JVM中的字符串常量池中,当创建一个新的String对象时,如果该字符串已经存在于常量池中,则直接引用该对象,否则创建一个新的对象。

String是字符串常量,而StringBuffer和StringBuilder是字符串变量。由String创建的字符内容是不可改变的,而由StringBuffer和StringBuidler创建的字符内容是可以改变的。

StringBuffer类

StringBuffer是旧版本JDK中提供的一个可变字符串类。它是线程安全的,适用于多线程环境。StringBuffer的主要特点是:

  • 可变性:可以修改字符串内容而不创建新的对象。

  • 线程安全:所有方法都被synchronized修饰,保证了多线程环境下的安全性。

  • 性能:由于线程安全的特性,性能相对较低。

https://blog.meowrain.cn/api/i/2025/07/04/z5zcqb-1.webp

StringBuilder类

StringBuilder是JDK 5引入的一个可变字符串类。它与StringBuffer类似,但不保证线程安全,因此在单线程环境下性能更高。StringBuilder的主要特点是:

  • 可变性:可以修改字符串内容而不创建新的对象。
  • 线程不安全:不保证线程安全,适用于单线程环境。
  • 性能:由于不需要同步,性能更高。

String为什么不可变?

String 类压根就没有提供任何 public 方法来修改那个 private final 的数组。你翻遍 String 类的所有方法,也找不到一个像 setValue(int index, char newChar) 这样的方法。

为什么String要设计成不可变

实现字符串常量池 (String Pool)

目的:这是最核心的原因,为了提升性能和节省内存。JVM 中存在一个字符串常量池,可以存放字符串对象。当创建多个值相同的字符串时,它们可以指向常量池中的同一个对象,从而避免重复创建。 前提:只有当字符串是不可变的,这种共享机制才是安全的。如果字符串是可变的,那么修改其中一个引用指向的内容,就会导致所有指向该对象的引用都受到影响,从而引发严重的程序逻辑混乱。

保证安全性 (Security)

场景:字符串在程序中被广泛用于存储敏感信息,比如数据库的用户名、密码、网络请求的地址等。 优势:不可变性可以防止这些关键值在创建后被意外或恶意篡改。例如,一个方法接收字符串参数进行安全校验,如果字符串是可变的,那么在校验通过后,其内容仍可能被外部修改,从而绕过安全检查。不可变性杜绝了这种风险。

天生线程安全 (Thread Safety)

场景:在多线程环境下,共享数据通常需要加锁等同步措施来避免冲突。 优势:因为 String 对象的状态永远无法被改变,所以它天生就是线程安全的。开发者可以放心地在多个线程之间共享同一个 String 对象,而无需任何额外的同步处理,这不仅简化了并发编程,也提高了程序的运行效率。

缓存哈希值 (Caching HashCode)

场景:字符串经常被用作 HashMap 或 HashSet 等集合的键(Key)。 优势:因为字符串不可变,所以它的哈希值(HashCode)也是固定不变的。String 类可以将计算出的哈希值缓存起来,当再次需要时直接返回,而不用重复计算。这保证了在使用 String 作为 Key 时,能够稳定、高效地在集合中进行存取操作。如果哈希值会变,集合的内部结构就会被破坏。


相关内容

0%