JDK常用类解读--StringBuffer、StringBuilder

上一篇博客讲到String对象一旦被创建该内容就不能被修改了如:

        String s = "hello world";
        s.substring(6);
        s.replace("hello","hi");
        String s1 = s+"java";
        System.out.println(s);//结果:hello world String中的方法只是返回新的字符串,并不改变原来的String对象
        System.out.println(s==s1);//结果:false 字符串拼接也只是创建了一个新的对象而已

  实际上String对象之所以不能被修改其本质因为String对象存储值的成员变量char value[] 无法被修改,如果希望多次修改String或者进行多次字符串拼接特别是在循环体中时,为了防止过多的创建和销毁对象,可以使用到 StringBuffer、StringBuilder;其实是先使用char[],然后可以对这个字符数组进行各种修改操作,最终new一个String对象并且将之前修改好的char[]的值作为String的value。

  StringBuffer、StringBuilder都继承了AbstractStringBuilder抽象类:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;//没有使用final private修饰,说明该引用可以指向其他char[]对象,同时也是可以被子类访问到的

    /**
     * The count is the number of characters used.
     */
    int count;

 

 

 

 接下来看看最常用的append方法,StringBuffer、StringBuilder虽然重写该方法,最终也还是调用的父类append:

//AbstractStringBuilder
public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);//检查value数组是否需要扩容,需要的话进行扩容
        str.getChars(0, len, value, count);//备份String对象中的char[]值到value中
        count += len;
        return this;
    }
//StringBuilder
@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}
//StringBuffer
@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

  StringBuffer、StringBuilder类的代码实现上基本一致,但是StringBuffer中的所有公开的方法有synchronized修饰,说明StringBuffer是可以保证线程安全的,当然StringBuilder没有加锁,效率自然更高,所以在多数情况下不需要考虑线程安全问题时应该使用StringBuilder。

 

再来来看看StringBuffer、StringBuilder的toString方法:

//StringBuilder
@Override
    public String toString() {
        // Create a copy, don't share the array 创建副本,不共享数组
        return new String(value, 0, count);
    }

//StringBuffer @Override public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }

   可以发现StringBuilder、StringBuffer的toString最后创建String对象使用的构造器不同,前者使用的构造器是将StringBuilder的char[] 重新创建一个副本作为String的值;后者是先创建副本,并使用toStringCache变量将副本缓存,然后调用String构造器直接将toStringCache引用的char[]与String共享,不需要在进行数组拷贝,算是一种优化,toStringCache同样是被private修饰并且不可修改,当调用StringBuffer其他的修改char[]方法(如append)时,toStringCache会被重新置为null。

   这里有个问题,为什么StringBuilder toString中char[]不能做缓存并与String共享,应该是因为StringBuffer是同步的,在调用toString()方法的时候,它的value数组不会被修改,而StringBuilder它没有同步,在调用toString()时无法保证成员变量不被修改(如果使用缓存,在创建对象String的同时,有可能该缓存会被其他线程清空),所以需要重新创建一个char[],尽量保证如果其他线程改变了这个char[],不会影响到结果String的生成。

 

 

原文地址:https://www.cnblogs.com/qzlcl/p/10864235.html