`
445822357
  • 浏览: 740294 次
文章分类
社区版块
存档分类
最新评论

StringBuilder源码分析

 
阅读更多

StringBuilder是平常编程中比较常用的JDK下的类之一。在字符串的拼接中发挥着重大的作用。可能很多人对于StringBuilder的认识并不深刻。这里通过我的理解来阐述一下StringBuilder。

1.为什么要使用StringBuilder?

这里很多人可能会说有“+”写出来的代码可能不是那么雅观,可能算做一个,另外更重要的原因是众所周知的性能。这在很多面试题里会屡试不爽的提在字符串拼接的情况下使用StringBuilder,在for循环下更是如此。why?这里归根结底是String的final特性决定的。如果细心的同学可以看一下String的源码中存储的数组就是final类型的。String本身是无法达到扩容的目的。

2.为什么StringBuilder可以得到性能上的提升。

StringBuilder内部也是一个char数组,这和String内部的存储实现无异。下面用具体的代码来看一下使用String和StringBuilder在性能上的差异和性能到底损失在什么地方。

    @Test
    public void test3(){
        String s = null;
        for(int i=0;i<1000;i++){
            s +=i;
        }
    }
    
    @Test
    public void test4(){
        StringBuilder builder = new StringBuilder();
        for(int i=0;i<1000;i++){
            builder.append(i);
        }
    }
    @Test
    public void test5(){
        StringBuilder builder = new StringBuilder(3000);
        for(int i=0;i<1000;i++){
            builder.append(i);
        }
    }
test3方法

采用最笨的+操作符,上面已经说String是final类型的,可以看一下中间会产生出多少中间对象,可以简单的算一下,本身循环1000次会有1000个对象,另外实现+操作后又产生1000个对象。最后垃圾回收多少对象?回收1999个对象。只保留最后一个s对象。

test4方法

采用不初始化初始容器的方式进行,这也是大部分程序员能做到的。这里会产生多少对象呢?在外面看来是1001个对象,其实不是这样的。这里又要看一下StringBuilder的初始容量是16。当i=13的时候出现了一次扩容,看一下内部的会用到System.arrayCopy来实现一个扩容机制。这里再回到StringBuilder内部的存储是采用char数组实现存储的,而这个char[]的初始容量就是16,这样当i=13的时候会发现原来的数组已经装不下了,这时候怎么办?这时候首先申请一个更大容量的数组,新申请数组的大小是多少呢?是(当前容量的大小+1)*2,也就是34,很多人说我这时候加入的字符串还是大于扩充的容量怎么办,这里做一个处理,就是如果发现加进来的字符串的大小大于当前新申请的容量,就以新加进来的字符串的大小作为申请容易的大小。这里说的有点绕,看代码会清晰很多。

回到我所说的test4例子,根据上面的分析,其实StringBuilder需要做几次扩容才能完成,这里性能损失会在哪,一个是数组copy,另外一个就是扩容产生的垃圾对象需要JVM回收都会造成性能损耗。算一下这里要扩容几次。要扩容8次,中间就会产生8个中间对象需要JVM回收,而越往后面垃圾对象越大。

test5方法

test5在test4上面的改进主要就是初始化容量,这么做的好处就是省去了8次扩容产生的性能损耗和JVM回收垃圾的时间。

结论

所以在知道当前你append字符串容量的情况下可以指定其大小,在某些场景下有不少的性能提升。上面的分析同样可以平移到ArrayList,HashMap等内部采用数组实现的结构中。

3.如何计算需要初始化容量的大小?

String类型好算一些,length就可以了。像一些int类型,long类型它们需要申请多少空间呢?举一个简单的例子,像int类型的1000在StringBuilder需要占几个?答案是4个,如果去看一下源码就知道,它其实是转成String存,当然内部并没有强转成String,而是用了getChars方法。里面用了一些小技巧来获得一些性能的提升,有兴趣的同学也可以去看一下StringBuilder的实现。

4.具体的性能有多大的提升?

这里有兴趣的同学可以去压测一下。






分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics