关于字符串拼接,我们一般使用+号对String类进行拼接,但实际上这是一种非常不高效的方法,而另一种方法就是使用StringBuilder类的append方法,这是一种非常高效的方式。
今天也是被面试官问到StringBuilder为什么比String拼接字符串速度要快,我回答了StringBuilder的append方法的复杂度是o(1)(回答错了),String类的 + 拼接方法复杂度是O(n),但是append的原理没有答上来,所以面试结束之后赶紧打开idea看源码,把了解到的一些知识总结一下吧。
首先新建一个StringBuilder的默认大小容量是16:我们可以看到这里调用了super方法,因为StringBuilder继承了AbstractStringBuilder类,所以我们跟踪到AbstractStringBuilder类里面看一下。
可以看到就是调用了父类的这个构造方法。OK,现在我们就来看一下append方法具体是怎么实现的。 我们一append(str)为例子看一下:
同样里面是直接调用了父类AbstractStringBuilder的append方法
我们来分析一下这个方法中的几个关键方法:
(1)ensureCapacityInternal(count + len):确保现在数组value能够装下拼接之后的字符串。
(2)putStringAt(count, str):关键方法,调用了String类里面的getBytes方法
然后调用了System.arraycopy()方法
这是一个本地方法,具体作用就是从源数组src取元素,范围为下标srcPos到srcPos+length-1,取出共length个元素,存放到目标数组中,存放位置为下标destPos到destPos+length-1,简单来说就是数组复制。
所以我们可以知道StringBuilder类的append方法底层是调用了System.arraycopy()完成字符串的拼接,其复杂度是O(n),n是要拼接字符串的长度。
接下来我们来讨论一下用+号进行字符串拼接:
我么都知道+号拼接字符串效率没有append()方法效率高,那这是为什么呢?假如现在有这样一条语句 str1+=str2;我们编译器在遇到这条语句时会调用StringBuilder(str1)产生一个StringBuilder对象,然后再调用这个对象的append(str2)方法对字符串进行拼接,最后调用toString()方法返回拼接好的字符串。所以+号的底层原理还是StringBuilder的append方法,但它的效率却低了不少,因为调用了两次append方法,还有一次是StringBuilder(str1)这里调用了一次append(str1)方法。
所以+号的复杂度是O(n+m);