zoukankan      html  css  js  c++  java
  • 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的生成。

     

     

  • 相关阅读:
    10款免费开源图表插件推荐
    jQuery中$.get()、$.post()和$.ajax()
    layer弹出层的iframe页面回调
    【转载】MSXML应用总结 概念篇
    【转载】MSXML应用总结 开发篇(上)
    【转载】MSXML应用总结 开发篇(下)
    【转载】MFC怎么封装CreateWindow
    【转载】MFC的Main函数跑哪去了
    【转载】C++创建对象的两种方法
    【转载】malloc内存分配与free内存释放的原理
  • 原文地址:https://www.cnblogs.com/qzlcl/p/10864235.html
Copyright © 2011-2022 走看看