StringBuider
一、StringBuilder和"+"的区别
如果连接字符串行表达式很简单(如顺序结构),那么"+"和StringBuilder类基本是一样的,但如果结构比较复杂,如使用循环来连接字符串,那么产生的Java Byte Code就会有很大的区别。
因为在Java中无论使用何种方式进行字符串连接,实际上都使用的是StringBuilder类。
在源程序中使用了"+",在编译时仍然会将"+"转换成StringBuilder。
如果创建StringBuilder对象的位置在for语句内部,这就意味着每执行一次循环,就会创建一个StringBuilder对象,虽然Java有垃圾回收器,但这个回收器的工作时间是不定的。如果不断产生这样的垃圾,那么仍然会占用大量的资源(Eden内存会被大量吞噬)。解决这个问题的方法就是在程序中直接使用StringBuilder类来连接字符串。
简单的测试:

运行结果:

注意到调用了100000次Thread.sleep(1),减去100000ms就是实际运行的时间。
因此看出,10万次的str操作,用String消耗了将近400s,而用StringBuilder只消耗了1.5s
在使用StringBuilder类时要注意,不要"+"和StringBuilder混着用,否则会创建更多的StringBuilder对象。
StringBuffer和StringBuilder的功能基本一样,只是StringBuffer是线程安全的,而StringBuilder不是线程安全的。因此,StringBuilder的效率会更高。
二、StringBuilder的toString()方法

上述代码中,CPU会一直忙于进行内存的分配工作,会导致机器的load过高
用StringBuilder类中的length来判断是否有数值,这样就避免了无谓的内存操作。

每次调用toString方法,会重新new一个String出来。
在java.lang.String的代码中,看最后一行,value并不是直接指向的,而是通过系统拷贝函数进行的内存操作


那为啥会通过内存拷贝的形式来进行toString呢,原因在于StringBuilder内部有两个核心的属性,这两个记录了String中的内容,是字符数组的形式。
这时候对于字符数组操作,通过内存拷贝是最快的方式了。
三、StringBuilder的capacity
StringBuilder默认的capacity是16个Byte,当我们append的内容超过16以后,它会自动扩容。因为这个扩容会导致复制,因此如果我们知道大概的大小,最好直接给出容量,这样免去很多复制操作,提高效率。
扩容方式:
1. 如果我们指定初始容量,比如StringBuilder str = new StringBuilder(20);那么之后每次扩容,都是以20为倍数;如果不指定,以16为倍数。
2. 使用默认str,如果append的内容超过16(但不超过32),那么增加一倍,str的capacity变成32;
3. 如果append的内容超过32,比如54,那么str的capacity直接为54;
4. 如果此时,再次append一些内容,总容量超过了32的倍数64,但是没有超过128,那么str的capacity为128;也就是它append后的容量必须超过当前容量(比如说54)的所对应的翻倍容量(比如16以下对应16,32以下16以上对应32,因此54对应64)的2倍后(也就是128),就按照append后的容量扩容,否则按照2倍递增的方式扩容。
浙公网安备 33010602011771号