String、StringBuffer与StringBuilder的区别,及实现原理

原文链接:https://blog.csdn.net/m_Tenderness/article/details/90758848

源码分析
String使用final关键字修饰可以知道String是不可变的类,String中字符数组的长度你定义多少,就是多少,不存在字符数组扩容一说。内部是final修饰的char[] value,表示String类不可被继承,且value只能被初始化一次。这里的value变量其实就是存储了String字符串中的所有字符。
StringBuffer和StringBuilder二者的源码以及append方法,二者都是AbstractStringBuilder的子类,也都实现了Serializable(可序列化)和CharSequence(char类型的可读序列)接口,AbstractStringBuilder 实现了Appendable(长度可增加)和CharSequence接口。

//String
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
    private final char value[];
    public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
}
//StringBuilder
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}
    
//StringBuffer
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    @Override
    private transient char[] toStringCache;
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
}

//AbstractStringBuilder 
abstract class AbstractStringBuilder implements Appendable, CharSequence{
	char[] value;
	int count;
	AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
}

String中单的subString方法在最后会使用new关键字创建一个新的对象,如果传入0也是new一个新的和原来相同长度相同内容的字符串返回。其他对字符串的操作方法也是创建一个新的String对象返回
StringBuffer上使用了synchronized 关键字加了同步锁证明它是线程安全的,而StringBuilder没有使用说明是线程不安全的

StringBuilder原理分析
内部调用父类的构造方法,内部是容量为16的字符数组。
StringBuilder的构造方法、append()和toString()方法

public StringBuilder(int capacity) {
        super(capacity);
    }
        public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
     public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }
        @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

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

在参数String类型的构造方法中,在本身字符串长度的基础上再增加16个字符长度,作为StringBuilder实例的初始数组容量,并将str字符串 append到StringBuilder的数组中。
这里的toString方法直接new 一个String对象,将StringBuilder对象的value进行一个拷贝,重新生成一个对象,不直接操作StringBuilder的value。
StringBuilder没有像String一样去重新new 对象,所以在频繁的拼接字符上省去了new 关键字的StringBuilder,不必每次都要重新开辟新的内存空间,其效率远远高于String类。

StringBuffer原理分析
StringBuffer是线程安全的高效字符串操作类,在StringBuilder上加了锁机制
StringBuilder的构造方法、append()和toString()方法

public StringBuffer() {
        super(16);
    }
    public StringBuffer(int capacity) {
        super(capacity);
    }
     public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }
     public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }
     @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
     public synchronized StringBuffer append(StringBuffer sb) {
        toStringCache = null;
        super.append(sb);
        return this;
    }
     @Override
    synchronized StringBuffer append(AbstractStringBuilder asb) {
        toStringCache = null;
        super.append(asb);
        return this;
    }
     @Override
    public synchronized StringBuffer append(CharSequence s) {
        toStringCache = null;
        super.append(s);
        return this;
    }
     @Override
    public synchronized StringBuffer append(CharSequence s, int start, int end)
    {
        toStringCache = null;
        super.append(s, start, end);
        return this;
    }

    @Override
    public synchronized StringBuffer append(char[] str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public synchronized StringBuffer append(char[] str, int offset, int len) {
        toStringCache = null;
        super.append(str, offset, len);
        return this;
    }
	@Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

StringBuffer比StringBuilder多了一个toStringCache域,用以去除toString方法的缓存
作用就是如果StringBuffer对象此时存在toStringCache,在多次调用其toString方法时,其new出来的String对象是会共享同一个char[] 内存的,达到共享的目的。但是StringBuffer只要做了修改,其toStringCache属性值都会置null处理。

总结
String 类不可变,内部维护的char[] 数组长度不可变,为final修饰,String类也是final修饰,不存在扩容。字符串拼接,截取,都会生成一个新的对象。频繁操作字符串效率低下,因为每次都会生成新的对象。
StringBuilder 类内部维护可变长度char[] , 初始化数组容量为16,存在扩容, 其append拼接字符串方法内部调用System的native方法,进行数组的拷贝,不会重新生成新的StringBuilder对象。
它是非线程安全的字符串操作类, 其每次调用 toString方法而重新生成的String对象,不会共享StringBuilder对象内部的char[],会进行一次char[]的copy操作。
StringBuffer 类内部维护可变长度char[], 基本上与StringBuilder一致,但其为线程安全的字符串操作类,大部分方法都采用了Synchronized关键字修改,以此来实现在多线程下的操作字符串的安全性。
其toString方法而重新生成的String对象,会共享StringBuffer对象中的toStringCache属性(char[]),但是每次的StringBuffer对象修改,都会置null该属性值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章