从源码深入分析Java中 StringBuffer和StringBuilder的区别

从源码深入分析Java中 StringBuffer和StringBuilder的区别?

  • StringBuffer和StringBuilder都继承自抽象类AbstractStringBuilder。
  • 存储数据的字符数组没有被final修饰,说明值可以改变,抽象类AbstractStringBuilder内部都提供了一个自动扩容机制,当发现长度不够的时候(初始默认长度是16),会自动进行扩容工作,扩展为原数组长度的2倍加2,创建一个新的数组,并将数组的数据复制到新数组,所以对于拼接字符串效率要比String要高。
  • 线程安全性:StringBuffer由于很多方法都被 synchronized 修饰了所以线程安全,但是当多线程访问时,加锁和释放锁的过程很平凡,所以效率相比StringBuilder要低。StringBuilder相反执行效率高,但是线程不安全。
  • 执行速度:StringBuilder > StringBuffer > String。

1. 继承关系分析

StringBuffer和StringBuiler都继承自AbstractStringBuilder类,JDK1.7源码如下:

/**StringBuffer类源码*/
public final class StringBuffer extends AbstractStringBuilder
    implements Serializable, CharSequence

/**StringBuilder类源码*/
public final class StringBuilder extends AbstractStringBuilder
    implements Serializable, CharSequence

/**AbstractStringBuilder类源码*/
abstract class AbstractStringBuilder
    implements Appendable, CharSequence

2. 动态实现扩容分析

StringBuffer的构造方法,JDK1.7源码如下:

	/**默认长度是16*/
    public StringBuffer()
    {
        super(16);
    }
	/**可以指定初始长度*/
    public StringBuffer(int i)
    {
        super(i);
    }
	/**变量长度+16*/
    public StringBuffer(String s)
    {
        super(s.length() + 16);
        append(s);
    }
	/**变量长度+16*/
    public StringBuffer(CharSequence charsequence)
    {
        this(charsequence.length() + 16);
        append(charsequence);
    }

StringBuiler的构造方法,JDK1.7源码如下:

	/**默认长度是16*/
    public StringBuilder()
    {
        super(16);
    }
	/**可以指定初始长度*/
    public StringBuilder(int i)
    {
        super(i);
    }
	/**变量长度+16*/
    public StringBuilder(String s)
    {
        super(s.length() + 16);
        append(s);
    }
	/**变量长度+16*/
    public StringBuilder(CharSequence charsequence)
    {
        this(charsequence.length() + 16);
        append(charsequence);
    }

抽象类AbstractStringBuilder扩容机制,JDK1.7源码如下:

    public void ensureCapacity(int i)
    {
        if(i > 0)
            ensureCapacityInternal(i);
    }

    private void ensureCapacityInternal(int i)
    {
        if(i - value.length > 0)
            expandCapacity(i);
    }

    void expandCapacity(int i)
    {
    	//扩展长度j = 为原数组长度的2倍加2
        int j = value.length * 2 + 2;
        if(j - i < 0)
            j = i;
        if(j < 0)
        {
        	//注意:这里可能会溢出,溢出后是负数,
            if(i < 0)
                throw new OutOfMemoryError();
            j = 2147483647;
        }
        value = Arrays.copyOf(value, j);
    }

由抽象类AbstractStringBuilder可知:StringBuffer和StringBuiler的扩容的机制在抽象类AbstractStringBuilder中实现,当发现长度不够的时候(默认长度是16),会自动进行扩容工作,扩展为原数组长度的2倍加2,创建一个新的数组,并将数组的数据复制到新数组。

3. 线程安全性分析

StringBuffer的相关方法,JDK1.7源码如下:

    public synchronized StringBuffer append(Object obj)
    {
        super.append(String.valueOf(obj));
        return this;
    }
    public synchronized String substring(int i, int j)
    {
        return super.substring(i, j);
    }
    public synchronized StringBuffer replace(int i, int j, String s)
    {
        super.replace(i, j, s);
        return this;
    }
    public synchronized StringBuffer delete(int i, int j)
    {
        super.delete(i, j);
        return this;
    }
    public synchronized int length()
    {
        return count;
    }

StringBuiler的相关方法,JDK1.7源码如下:

    public StringBuilder append(Object obj)
    {
        return append(String.valueOf(obj));
    }
    public StringBuilder replace(int i, int j, String s)
    {
        super.replace(i, j, s);
        return this;
    }
    public StringBuilder delete(int i, int j)
    {
        super.delete(i, j);
        return this;
    }
    public volatile int length()
    {
        return super.length();
    }

由源码中我们可知:

  • StringBuffer几乎都是调用的父类的方法而且都加了synchronized修饰,所以是线程安全的;但是平凡的加锁和释放锁导致性能降低,执行速度上比StringBuffer要慢。
  • StringBuilder所有方法都没有用synchronized关键字修饰,所以线程不安全,但是由于没有加锁释放锁导的过程,执行速度上比StringBuffer要快。

……
帮助他人,快乐自己,最后,感谢您的阅读!
所以如有纰漏或者建议,还请读者朋友们在评论区不吝指出!
……
个人网站…知识是一种宝贵的资源和财富,益发掘,更益分享…

你可能感兴趣的:(Java)