String StringBuffer Stringbuilder


String StringBuffer Stringbuilder的区别

1. 可变性

String 是不可变的(后面会详细分析原因)。

StringBuilderStringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 finalprivate 关键字修饰,最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的方法比如 append 方法

2. 线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilderStringBuilderStringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacityappendinsertindexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

3.性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

执行速度由快到慢:StringBuilder > StringBuffer > String

4. String为什么不可变

注意:String 类中使用 final 关键字修饰,所以String不可变,并不是String不可变的真正原因!

我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的(final 修饰引用类型变量的情况)。

String 真正不可变有下面几点原因:

  1. 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
  2. String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

参考文献:

如何理解 String 类型值的不可变? - 知乎提问

不可变有什么好处

我们可以看这段代码

public class Test01 {
    public static void main(String[] args) {

        String s1 = new String("aaa");
        String s2 = Test01.appendStr(s1);
        System.out.println(s1);
        System.out.println(s2);

        StringBuffer sb1 = new StringBuffer("aaa");
        StringBuffer sb2 = Test01.appendStringBuffer(sb1);
        System.out.println(sb1);
        System.out.println(sb2);

        StringBuilder sb3 = new StringBuilder("aaa");
        StringBuilder sb4 = Test01.appendStringBuilder(sb3);
        System.out.println(sb3);
        System.out.println(sb4);
    }

    public static String appendStr(String s){
        s+="bbb";
        return s;
    }

    public static StringBuffer appendStringBuffer(StringBuffer stringBuffer){
        return stringBuffer.append("bbb");
    }

    public static StringBuilder appendStringBuilder(StringBuilder stringBuilder){
        return stringBuilder.append("bbb");
    }
}

输出:

aaa
aaabbb
aaabbb
aaabbb
aaabbb
aaabbb

如果程序员不小心像上面例子里,直接在传进来的参数上加”bbb”,因为Java对象参数传的是引用,所以可变的的StringBuffer参数就被改变了。可以看到变量sb在Test.appendSb(sb)操作之后,就变成了”aaabbb”。有的时候这可能不是程序员的本意。所以String不可变的安全性就体现在这里。


Author: qwq小小舒
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source qwq小小舒 !
  TOC