StringBuffer与StringBuilder

在生产中不要使用String进行太多的拼接。
例如

String a = "hello";
String b = "world";
String str = a + b;

String字符串的拼接的过程中会创建很多个临时字符串。
String是一种常量,字符串中的字符是通过一个final修饰的char[]数组来保存的。
String字符串的值一旦确定则不可修改。

我们进行的所有字符串的拼接、替换、拆分、插入、截取等等方法,
实际上都是在内存中生成了新的字符串对象,并没有在原有字符串的值上做修改。

对于字符串的拼接,可以使用StringBuffer和StringBuilder进行优化。

  • StringBuffer和StringBuilder是两种可变长字符串,
  • 是具有缓冲功能和可修改的特性。

字符串的内容可能会经过很多次的调整,
例如对字符串中的字符进行增删改查。
传统的String会把过程中的每一步临时修改都生成一个新的字符串,
但是这些字符串都没有实用价值,而且还会长时间占用内存。


缓冲的优化思路是:

  1. 在字符串修改的过程中,不会生成新的String对象。
  2. 而是把要生成的字符串内容临时保存在一个缓冲数组中。
  3. 等修改完毕确认要生成字符串的时候直接生成一次最终的结果即可。

StringBuffer和StringBuilder的异同点:

  1. 它们都是可拼接的字符串,都继承同一父类,具有相同的功能。
  2. StringBuffer线程安全,但效率低
    StringBuilder线程不安全,但效率高

源码分析:

append的实现

  1. 基本使用
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("你好");
        sb.append("世界");

        System.out.println(sb.toString());
    }
  1. StringBuffer的append源码:在每一次调用append方法时,都会将toStringCache设置为null
    @Override
    public synchronized StringBuffer append(String str) {
        //拼接要修改字符数组,所以将缓冲置为空
        toStringCache = null;
        //调用父类的append方法
        super.append(str);
        return this;
    }
  1. 1 toStringCache:根据java的注释可以知道,他是最后一个调用toString方法生成的字符串内容,只要字符串发生了改变,这个缓冲就会被清空。
    相当于一个缓冲区,避免多次拷贝真正的char数组
    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;
  1. 2 toString方法:如果此时缓冲为空的话,就将父类中真正的value字符数组拷贝过来,之后直接用自己的字符数组创建String对象
    @Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }
  1. 3 父类AbstractStringBuilder的append方法
    public AbstractStringBuilder append(String str) {
        //如果为null的话,就返回一个appendNull的结果,点进去看一下就知道,这里就不再看了
        if (str == null)
            return appendNull();
        //获得要拼接的字符串长度
        int len = str.length();
        //确保字符数组长度够用,不够就扩容,这里不做过多赘述,如果容量不够则value = Arrays.copyOf(value,newCapacity(minimumCapacity));来进行扩容
        ensureCapacityInternal(count + len);
        //将str从0开始到len的位置拷贝到value数组中,从count位置开始存放(aka 将str拼接到value后面)
        str.getChars(0, len, value, count);
        //然后增加value的长度
        count += len;
        //返回
        return this;
    }
posted @ 2020-08-28 11:21  微花  阅读(191)  评论(0)    收藏  举报

Loading