手记

String,StringBuilder和StringBuffer

在 Java 编码中会非常频繁的使用字符串。字符串对应的操作类有3个,分别是StringStringBufferStringBuilder

异同
类型 final 变量/常量 线程安全 效率
String 常量 -
StringBuffer 变量 线程安全
StringBuilder 变量 线程不安全

下图是三种类型的UML类图:

从图片可以看出,StringBufferStringBuilder非常相似,其实两者的区别也仅仅在于StringBuffer中的方法是用synchronized修饰的,即通过锁来实现线程安全。

效率

上表中已经介绍了三种类型的效率,下边通过代码,直观的看一下效果。

public class TestDemo
{
    private final int LOOP_NUM = 20000;
    private final String STRING_ITEM = "test_string_time";

    public static void main(String[] args) {

        new TestDemo().test();
    }

    public void testString(){
        String string = "";
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < LOOP_NUM; i++){
            string += STRING_ITEM;
        }
        long endTime = System.currentTimeMillis();
        System.out.print("String:" + (endTime - startTime) + "    ");
    }

    public void testStringBuffer(){
        StringBuffer sbf = new StringBuffer();
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < LOOP_NUM; i++){
            sbf.append(STRING_ITEM);
        }
        sbf.toString();
        long endTime = System.currentTimeMillis();
        System.out.print("StringBuffer : " + (endTime - startTime) + "    ");
    }

    public void testStringBuilder(){
        StringBuilder sbu = new StringBuilder();
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < LOOP_NUM; i++){
            sbu.append(STRING_ITEM);
        }
        sbu.toString();
        long endTime = System.currentTimeMillis();
        System.out.print("StringBuilder : " + (endTime - startTime) + "    ");
    }

    public void test(){
        for(int i = 0; i < 5; i++){
            testString();
            testStringBuffer();
            testStringBuilder();
            System.out.println();
        }
    }
}

运行结果如下:

String:6300 | StringBuffer : 2 | StringBuilder : 2
String:5555 | StringBuffer : 2 | StringBuilder : 0
String:5563 | StringBuffer : 2 | StringBuilder : 2
String:5553 | StringBuffer : 2 | StringBuilder : 2
String:5565 | StringBuffer : 1 | StringBuilder : 1

可以看到String的效率远远低于StringBufferStringBuilder

剖析StringBuffer

1)StringBuffer的构造器

使用StringBuffer的无参构造器,则会分配一个长度为16的字符串缓冲区。如果使用String参数构造器,则是分配长度为入参长度+16的字符串缓冲区。

    public StringBuffer() {
        super(16);
    }

    public StringBuffer(int capacity) {
        super(capacity);
    }

    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

2)append 实现

StringBuffer中的实现如下。

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

可见,此处是使用synchronized关键字进行修饰的,其实际逻辑是在父类中的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));
        }
    }

从代码可知,当append进来新的字符串的时候,会判断当前缓冲区是否能够容纳完整字符串,如果不能,则调用Arrays.copyOf方法通过数组复制实现缓冲区的扩展。

此处可能会有疑问,频繁调用Arrays.copyOf方法进行数组复制,不会产生性能问题吗?其实Arrays.copyOf的性能消耗是比较小的,其内部是调用System.arraycopy方法来实现的。而System.arraycopy是Jni调用本地方法,速度非常快。

    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;
    }
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
参考资料

http://www.cnblogs.com/fancydeepin/archive/2013/04/23/min-snail-speak_String-StringBuffer-StringBuilder.html

http://blog.csdn.net/chy555chy/article/details/52386608

5人推荐
随时随地看视频
慕课网APP