Java源码分析——String、StringBuffer、StringBuilder类(二)——AbstractStringBuilder抽象类

版权声明:博主GitHub地址https://github.com/suyeq欢迎大家前来交流学习 https://blog.csdn.net/hackersuye/article/details/84106275

    在Java中,关于字符串类分为两种,一种是上篇博客讲的String类,即不可变字符串类,另外一种则是可变字符串类,即AbstractStringBuilder抽象类的子类,StringBufferStringBuilder类,其中的两者的区别体现于如下代码:

 StringBuilder builder=new StringBuilder("123");
 System.out.println(builder==builder.append("456")); //true
 String s=new String("111");
 System.out.println(s==s.concat("222"));//false

    当两者追加一个字符或者字符串的时候,AbstractStringBuilder类的地址是不变的,而String类是总是改变的,也就是String总会创建一个新的String类,关于AbstractStringBuilder类追加字符串是仅扩充其内部的存贮字符的value数组的大小,而整个实例的地址是不变的,源码如下:

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;
    }

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

    从源码中可以看出,AbstractStringBuilder 类追加操作底层调用了java.lang包下的Arrays类的copyOf方法来进行扩充数组以及复制的,最后返回this变量,返回自身。而AbstractStringBuilder 类不仅提供了value数组的扩充操作,也提供了缩小的操作:

public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
    }

    而newCapacity方法每次扩充的大小是原来的value数组长度的2倍+2:

private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;
    int count;
}

    其中在AbstractStringBuilder 类中count属性是用来记录value数组中所用空间的长度,也就是代表着字符串的长度,而在String类中是没有这个属性的,String类的value数组的大小是根据所要保存的字符串的长度而固定的。整个AbstractStringBuilder 类实现了String类中的功能,关于AbstractStringBuilder类与StringBufferStringBuilder类关系如下:
在这里插入图片描述

    从上图看出,他们之间是父子类的关系,而StringBuilder类则是直接实现的AbstractStringBuilder抽象类,在其内部调用的都是其父类的方法,而StringBuffer类则是在StringBuilder类的基础上考虑到了多线程的情况,它是线程安全的,就比如两者重写的toString方法:

//StringBuilder类、
public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }
    
//StringBuffer类
private transient char[] toStringCache;//起一个缓存的作用,不被序列化
public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

    两者都是返回一个新的String对象,StringBuffer类加了同步,让其保证是线程安全的。两者也都实现了写入读取输入流与输出流(以StringBuilder为例):

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        s.defaultWriteObject();
        s.writeInt(count);
        s.writeObject(value);
    }

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        count = s.readInt();
        value = (char[]) s.readObject();
    }

    综合来看,三者的效率:StringBuilder>StringBuffer>String类,因为StringBuilder与StringBuffer两者实现相同,但StringBuffer类兼顾了多线程的情况所以要比StringBuilder慢一些,而String类每次更改都要创建一个新的String对象(前提常量池中没有该对象),所以要比前两者慢一些,所以它们的选取策略如下:

  1. 当是少量的字符串操作且是单线程时时,采用String类;
  2. 当是大量的字符串操作且是单线程时,采取StringBuilder类;
  3. 当是多线程的时候,采用StringBuffer类;

猜你喜欢

转载自blog.csdn.net/hackersuye/article/details/84106275