为什么StringBuffer比String在拼接的时候效率高?

简单了解String与StringBuffer

什么是StringBuffer?

可变的字符串对象,底层是一个char数组,但是该char数组是可变的,并且可以自动扩容。

字符串缓冲区

StringBuffer和StringBuider,StringBuffer和StringBuider的默认容是“16”。

StringBuffer与String的区别

String:不可变的字符序列,存储在字符串常量池中。

StringBuffer:可变的字符串对象。

StringBuffer可变的原理

创建StringBuffer的时候,预先在内存中申请一块空间,存储字符序列,如果预留空间不够用,则自动扩容存储更多的字符序列。


源码解析

源码继承抽象类AbstractStringBuilder 
public final class StringBuffer
    extends AbstractStringBuilder
    implements Serializable, CharSequence{  代码……  }

(这里删除了源码,只保留了类头)

 ensureCapacityInternal()  --- 扩容

    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

StringBuffer的底层结构和String一样都是char[]数组类型,不同的是StringBuffer有他的扩容机制,默认容量为16,当我们的内容大于我们的数组长度时,会将我们的容积扩大。这里调用了Arrays.copy()

  public static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

Arrays.copy()的底层也是创建了一个新的数组对象,并赋值了扩大后的长度,返回新的数组给我们。

append() --- 添加字符
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

append方法就是添加字符,返回新的截取内容,当长度不够时进行扩容。

toString()

toString方法就是创建一个新的String对象,赋值当前内容

@Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

为什么效率高?

都是创建对象,为什么StringBuffer效率要比String效率高?

不考虑扩容机制的前提下,String和StringBuffer的效率是否是一样的呢?

对于这个问题,我们从字节码的角度来分析。将我们的代码生成CLASS文件,再反编译成汇编码(这里我不会反编译)

    Code:
       0: ldc           #2                  // String a
       2: astore_1
       3: iconst_0
       4: istore_2
       5: iload_2
       6: bipush        10
       8: if_icmpge     37
      11: new           #3                  // class java/lang/StringBuilder
      14: dup
      15: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      18: aload_1
      19: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: ldc           #6                  // String b
      24: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_1
      31: iinc          2, 1
      34: goto          5
      
      37: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      40: ldc           #9                  // String ========================
      42: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      
      45: new           #3                  // class java/lang/StringBuilder
      48: dup
      49: ldc           #11                 // String c
      51: invokespecial #12                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      54: astore_2
      55: iconst_0
      56: istore_3
      57: iload_3
      58: bipush        10
      60: if_icmpge     76
      63: aload_2
      64: ldc           #13                 // String d
      66: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      69: pop
      70: iinc          3, 1
      73: goto          57
      76: return

通过汇编码,我们明显的看到,String它在拼接对象的时候是循环创建StringBuffer对象再new一个String对象,而StringBuffer则一直循环的是append方法,最后再返回一个new String对象,所以比String效率高。

    public static void getStr()
    {
        String str = "aaa";
        System.out.println(str);
        str = str + "bb";
        System.out.println(str);
    }

如果运行这段代码会发现先输出“aaa”,然后又输出“aaabb”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“aaa”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“bb”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
 

这只是我对今日份学习的分享

原版博客在这里icon-default.png?t=N7T8https://blog.youkuaiyun.com/qq_37120563/article/details/121640676?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169789629516800222869371%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=169789629516800222869371&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-121640676-null-null.142%5Ev96%5Epc_search_result_base2&utm_term=StringBuffer%E4%B8%BA%E4%BB%80%E4%B9%88%E6%95%88%E7%8E%87%E6%AF%94String%20%E9%AB%98&spm=1018.2226.3001.4187

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尧星云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值