Java中String与StringBuilder处理字符串效率存在差异的源码分析

申明一点:这篇博客只讨论stringbuilder中append(String str)方法;请看清楚,参数类型为String;

首先:字符串实际上就是一个char数组,也就是说String对象的值是保存在char[]中的;

存储具体值的char[]

在String中:

Java中String与StringBuilder处理字符串效率存在差异的源码分析

可以看到在String中存储字符串的是用final修饰的不可变char[];

在StringBuilder中:其构造方法是调用的父类AbstractStringBuilder的构造方法,存储字符串的也是一个char数组,具体的定义:

Java中String与StringBuilder处理字符串效率存在差异的源码分析

在StringBuilder中存储字符串的是一个可变char[];


StringBuilder中append(String str)的源码

Java中String与StringBuilder处理字符串效率存在差异的源码分析

StringBuilder 在使用append(String  str)方法时调用了其父类的append(String str)方法;

这其中有2行关键代码:

第一个是方法:ensureCapacityInternal(count + len);

第二个是:String类的getchars()方法;

看到这里大家或许会有疑问,因为最后还不是调用的String类的getchars()来生成的新字符串吗??那既然这样为什么会说StringBuilder的效率比较高呢??why??

先不管那么多,上String类的getchars()源码再说:

Java中String与StringBuilder处理字符串效率存在差异的源码分析

System.arraycopy()是native方法,没法看源码了,到这儿也就到头了;

从arraycopy方法的注释来看:意思是将 value的值复制到char数组dst中,再对应到append调用getchars所传的参数来看,是将str的值复制到value(char数组)中;(对照append方法中调用getchars()时传递的参数方便理解)

看着这里大家心里都应该有点那啥数了。。

因为String中字符串数组value是final的(不可改变的),而StringBuilder是可变数组;所以StringBuilder比String快的原因,是因为,每次用String处理字符串时,都要创建一个数组,而StringBuilder则不用只需要在动态char数组后添加字符就行;这样StringBuilder就比String快。

看起来这样解释好像没有问题。。。。不过未完待续,先出去撸上一把,回来再续写,。。


======================继续分析=====================================

有点小激动,居然有人看了我的博客。继续努力写。。。。

上面的解释中有一个疑点:如何保证动态数组有足够大的空间给新添加的字符串???他对存储字符串的数组是不是做了些什么???

讲到这里我们先了解一下,StringBuilder的构造方法;

讲一下其中的2种构造方法,一个是无参构造,一个是带参构造(参数类型为String);

Java中String与StringBuilder处理字符串效率存在差异的源码分析

Java中String与StringBuilder处理字符串效率存在差异的源码分析

很明显,不管是在无参构造还是在带参构造:在初始化char数组中始终预留了16个长度的空间;

现在我们来理解一下2个很重要的成员变量:

Java中String与StringBuilder处理字符串效率存在差异的源码分析

count:注释写的很明显:就是字符串的长度比如:

StringBuilder sb = new StringBuilder(“abcde”);那么sb对象的count为:5,因为有五个字符,这个很好理解;

Java中String与StringBuilder处理字符串效率存在差异的源码分析

value.length 的值是什么呢?首先我们先来看:value是一个char数组;还是以上面的sb为例:

“abcde”这五个字符都是存储在数组value中的,value.length:表示value这个数组的长度,因为留有16个空位所以整个数组的长度为21,也就是说:value.length=21

现在做一个综述:count:表示字符的个数;value.length:表示存储字符数组的长度(是数组的长度);

好了回到正题来,我们是如何保证存储StringBuilder对象的动态数组如何保证可以有足够的空间容纳下新加字符???

其实我们忽略了append()中调用的另一个方法:

Java中String与StringBuilder处理字符串效率存在差异的源码分析

(对比看上面的append方法)这两个参数:count:表示StringBuilder对象的字符个数,len:表示新添加的字符个数;这两个相加就表示:合并后总的字符数;举个列子:

StringBuilder sb = new StringBuilder(“abc”);

sb.append("de");这个例子中:count = 3;len = 2;合并后总字符数为 5;

接下来我们再看看这个方法里面是卖的什么狗皮膏药。。

Java中String与StringBuilder处理字符串效率存在差异的源码分析

很很简单的判断:就是判断合并后的总字符数是不是比原来存储StringBuilder对象的数组长度小,如果比原来的数组小,那很简单,原来的数组不用动,直接用就可以,不用创建新的数组;在这种情况下可以说,StringBuilder的效率比String高;

but!!!but !!!but 。。。如果合并后的总字符数超过了,存储StringBuilder对象数组的长度,那就要将StringBuilder得值复制到另外足够大的数组中了;在这种情况下的话。。。那和String那条咸鱼有什么区别?????!!!!!!!!!!根本就没有嘛Java中String与StringBuilder处理字符串效率存在差异的源码分析Java中String与StringBuilder处理字符串效率存在差异的源码分析

其实回到上一个问题:如何保证新加进来的字符有足够空间其实看到这里也就有了答案。。

所以说StringBuilder的效率不一定非得比String处理字符串的效率高;