String、StringBuffer和StringBuilder它们三者的区别,是面试官们最爱问的问题之一,它们之间到底有什么区别呢?
下面我们就做一下详细说明。
一、值可变性
- String 是字符串常量,字符串长度不可变。
- StringBuffer和StringBuilder都是可变类,它们在字符串变更的时候不会产生新的对象。
查看源码可以发现,String类是被 final 修饰的,String内部的 value 也是被 final 修饰的。因此,每次修改String的值时,如果该值在常量池中不存在时,都会在常量池中产生一个新的字符串,并重新指向这个新的字符串。
二、线程安全
- String是不可变类,因此它是线程安全的。
- StringBuffer是线程安全的,因为它的每个方法都加了 synchronized 关键字。
- StringBuilder不是线程安全的。
三、性能
在String的类注释上写得很清楚,String是一个常量,在其创建之后就不能被改变。
- String在拼接字符串和修改字符串的时候,每次都需要在常量池中创建和重新分配内存,丢弃原来的字符串,最后将指针指向新字符串,因此它的性能是最低的。
- StringBuffer具有可变性,可以直接修改字符串,因此它的性能要比String高。但StringBuffer加了同步锁,是堵塞的,对性能有一定影响。
- StringBuilder也具有可变性,也可以直接修改字符串,并且无堵塞。因此,StringBuilder的性能在这三者之中是最高的。
四、数据存储
网上经常会有这么一道面试题,String s = new String("abc"); 创建了几个对象?
首先看常量池中有没有字符串"abc",没有就分配空间创建一个字符串"abc"。
对象都是在堆上创建的,String对象创建后,就把常量池中的"abc"拷贝到堆内存空间中。
s是引用变量,指向新创建的对象。
我们使用最频繁的是 String s = "abc";引用变量s直接指向常量池中的字符串"abc",因此它是存储在常量池中。
StringBuffer和StringBuilder存储在堆内存空间,都继承自AbstractStringBuilder类,创建对象不指定容量时,默认容量为16。
如果操作少量的字符串,建议使用String;如果在单线程中操作大量的字符串,建议使用StringBuilder;如果在多线程中操作大量的字符串,涉及到线程安全,那么就使用StringBuffer。千万不要再使用String对象进行+++了,最费性能。
评论区