关于 String,StringBuilder,StringBuffer

Posted rabbitblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于 String,StringBuilder,StringBuffer相关的知识,希望对你有一定的参考价值。

关于 String,StringBuilder,StringBuffer 的讨论,已有很多文章;在这里,我希望能刨根问底,更进一步的理解其中的原理。

  • String

   String 是final类型,不可继承的类;内部存储是字符数组(char[]),也是final ,不可更改;

/** 源码中 String 类的声明 */
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

 

  我们知道 final 修饰变量,只能被赋值一次,赋值成功后,不可再重新赋值。这意味怎么什么呢?先看一下下面的例子:

public static void main(String[] args) {
        String a = "sdfsdklfjdskl1245";
        String b = "1234567489123";
        String c = a + b;
        System.out.println(c);
    }

  这里声明三个字符常量,在初始化时,b 是字符数组常量,而 c 则是两个常量字符的连接;下面是反编译后的信息:

技术分享图片

根据描述信息,c 变量是两个字符串连接的副本。(小弟知识范围有限,若上述代码解读有误,还请指正,不胜感激)

  如果字符串直接拼接,又是怎样呢?

  

public static void main(String[] args) {
        String a = "this is a" + " simple " + "test";
        System.out.println(a);
    }

  看看编译后的代码解析:

  技术分享图片

  编译过程做了优化,这里只产生了一个变量。

  所以 String 字符串的拼接,关键在于字符串连接底层实现方式;字符串的实现是不可变字符数组,那拼接又是对字符数组怎样的操作呢?是数组拷贝?还是其他方式,有待考究... ...

  字符串拼接性能低效又是怎么回事呢?请看下面例子:

    @Test
    public void testString1() {
        String a = "123456";
        for (int i=0; i<10; i++) {
            a += "dfdsfdsfds";
        }
        System.out.println(a);
    }

 

  上面代码中,我们初始化了常量 a,并且在循环里面做了多次字符串的拼接,最终 a 的指针地址指向了字符串拼接后的结果。这里存在以下问题:

    1、字符拼接过程产生了一定的字符数组;且是不可修改的。

    2、每次改变字符串的值,就要重新生成一个String对象,让后将指针指向新的对象。

    3、多余的对象一定程度上增加了GC的工作量。

  综上,String 字符串拼接存在一定的性能消耗,但还不足以说性能低效;有比较才有优劣,再看看 StringBuilder 和 StringBuffer 内部又是怎么玩的。

  • StringBuilder

  StringBuilder 内部存储是字符数组,是可修改的;查看父类:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

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

  添加字符串的方法是append,看看具体实现:

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

 

public static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

  以上所有源码都是jdk 9,这里对字符数组做了拷贝,底层的数组拷贝实现方法:

public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

  可以看到,底层调用 System.arraycopy 方法,而 arraycopy 方法是调用底层 C 语言实现的。

  通过上面的源码,得出一些结论:

    1、StringBuilder 在字符串拼接过程中,是对字符数组的修改;

    2、append 方法对数组做了动态扩容;

    3、最终实现调用 C 语言的方法;

  与 String 相比,由于 StringBuilder 是对数组的动态扩容,减少了中间对象的生成,在一定程度上性能较优。

  • StringBuffer

  StringBuffer 与 StringBuilder 都继承了 AbstractStringBuilder;

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;

 

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

  不同的是 StringBuffer 添加了同步锁,是线程安全的;

小结:

  在字符串拼接上,不考虑线程安全的情况下 StringBuilder 由于 StringBuffer,StringBuffer 优于 String;StringBuffer 是线程安全的。

以上是关于关于 String,StringBuilder,StringBuffer的主要内容,如果未能解决你的问题,请参考以下文章

关于String的equals问题和StringBuilder问题

关于Java基础知识 String StringBuffer StringBuilder三者的区别

关于String-StringBuffer-Stringbuilder的知识点

String,StringBuilder和StringBuffer区别

关于 String 自我理解

String,StringBuffer,StringBuilder的区别