String、StringBuilder、StringBuffer的比较

经常我们会对Sting/stringBuffer/StringBuilder 几个区分不清楚,所以写一篇博客总结一下:

String的值是不可修改的,并且每次对String操作都会生成新的对象,浪费大量的空间;
Stringbuffer值是可以改变的,效率一般,线程安全
StringBuilder的值可以改变,效率较高,线程不安全

1.三者值的可变性

String不可变,是因为在String底层实际上是一个字符数组,是定长的。
来看一下String的原码:

/** The value is used for character storage. */
    private final char value[];

 public String(char value[]) {
    
    
        this.value = Arrays.copyOf(value, value.length);
    }

可以看出长度是根据定义的字符串的长度来规定的,所以,他的长度是没有办法改变了。对String进行操作,会生成新的对象,又是新的数组。设想一下如果在一个循环里面,使用String来做改变,那浪费了很多的空间呢。
我们再来看一下StringBuilder和StringBuffer的源码:

public StringBuilder(String str) {
    
    
        super(str.length() + 16);
        append(str);
    }
 public StringBuffer(String str) {
    
    
        super(str.length() + 16);
        append(str);
    }

可以看出来Stringbuffer和StringBuilder的值是可以改变的。

2.String、StringBuffer和StringBuilder之间的继承关系

在这里插入图片描述
我们可以从三者的源代码来观察三者的继承关系。

3.String、StringBuffer、Stringbuilder的效率问题

首先,stringbuilder是在StringBuilder之后创造的,如果不提线程安全,那么StringBuilder当然是最快的。
然后我们再来看看String。

String str="hello"+"world";//代码1
String s1="hello";
String s2="world";
String s12=s1+s2;//代码2
StringBuilder sb=new StringBuilder(s1);
sb.append(s2);//代码3

我们观察上面的代码:代码1是常量的+操作,代码2是变量的+操作;
代码1:其实在编译阶段就将代码"hello"+"world"连接起来,并指向堆里面的字符串对像了,运行的时候,从堆里面拿出来。存放在局部变量str中。看起来就是取和放的操作。
代码2:当String使用+操作的时候,实际是分为三步的:
(1)Stringbuilder temp=new StringBuilder(s1);
(2)temp.append(s2);
(3)str=temp.toString();
仅仅是一个+号就做了这三步,同时创建了String对像和Stringbuilder对像,假如循环几万次,那会创建几万个两种对像,岂不是很浪费时间和空间。
代码3:在底层做的就是将字符数组的长度不断扩大,然后将新内容粘贴在原来的数组后面。只是做了扩容和的事情。
总结:Stringbuilder、Stringbuffer使用append的效率最高。

4.String、StringBuffer、StringBuilder的安全性问题

为什么Stringbuilder线程不安全,而stringbuffer是线程安全的呢?我们可以去看两者的源代码。在Stringbuffer中很多方法都是被Synchronized修饰的。中所周知,方法加了Synchronized修饰,那就是给加了一把锁,当一个对象拿到了这把锁才能够进行方法内的操作,而此时其他的线程就不可以拿到这个锁,不能操作,不会造成不安全的现象。当然单线程的话就没人抢锁了,Stringbuffer和Stringbuilder一样安全。
而String,他的值都不能被改变,被改变了就会生成一个新的对象,那他肯定是安全的啦。

猜你喜欢

转载自blog.csdn.net/weixin_43815275/article/details/113846296
今日推荐