在Java面试中经常会问到String、StringBuffer、StringBuilder的区别,很多同学不是很清楚三者的区别,下面我就来详解String、StringBuffer 和 StringBuilder 的区别@mikechen
1.区别1:可变与不可变
String是final类不能被继承且为字符串常量,而StringBuilder和StringBuffer均为字符串变量。
在Java中字符串使用String类进行表示,但是String类表示字符串有一个最大的问题:字符串常量一旦声明则不可改变,而字符串对象可以改变,但是改变的是其内存地址的指向。
所以String类不适合于频繁修改的字符串操作上,所以在这种情况下,往往可以使用StringBuffer类,即StringBuffer类方便用户进行内容修改。
2.区别2:线程安全性
先说结论,String:线程安全,StringBuffer:线程安全,而StringBuilder:是线程不安全的。
为什么?String、StringBuffer线程安全?StringBuilder线程不安全?
1)首先,我们先看String
对于String来说,是把数据存放在了常量池中,因为所有的String,默认都是以常量形式保存,且由final修饰,因此在线程池中它是线程安全的。
因为每一个String当被创建好了以后,他就不再发生任何变化,所以是线程安全的。
2)其次,我们再看StringBuffer和StringBuilder
StringBuffer 的所有公开方法都是 synchronized 修饰的,具体示例如下:
@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
所以,在多线程的情况下,StringBuffer 是线程安全的,而 StringBuilder 并没有 Synchronized修饰,是线程不安全的。
3.区别:性能
StringBuffer 每次获取 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串,如下代码示例:
@Override public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串,如下代码示例:
@Override public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }
所以,缓存冲这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个toString 方法仍然是同步的。
3.区别3:性能
性能:运行速度快慢为:StringBuilder > StringBuffer > String。
为什么String最慢?
因为String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
看一段代码示例:
String str="abc"; System.out.println(str); str=str+"de"; System.out.println(str);
JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了。
str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。
所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
为什么StringBuilder > StringBuffer?
原因很简单:既然 StringBuffer 是线程安全的,它的所有公开方法都是同步的,方法上都加有Synchronized,所以每次获取方法都需要加锁然后再释放锁,所以性能会降低。
同样道理StringBuilder 是没有对方法加锁同步的,所以毫无疑问,StringBuilder 的性能要远大于 StringBuffer。
总结
String 是不可变的,而 StringBuffer 和 StringBuilder 是可变类。
StringBuffer多线程安全,但是加了synchronized,其效率低,故适用于多线程下,并发量不是很高的场景
StringBuilder没有加任何锁,其效率高,适用单线程场景,但同时也适用于高并发场景中,提高高并发场景下程序的响应性能,至于线程安全问题可以通过其它手段解决,如ThreadLocal,CAS操作等。
作者简介
陈睿|mikechen(个人微信:mikechen68),10年+大厂架构经验,曾就职于阿里巴巴、淘宝、百度等一线互联网大厂。
以上!
关注作者「mikechen」公众号,获取更多架构面试干货!

后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》,后台回复【面试】即可获取《史上最全阿里Java面试题总结》