在String你还需要知道这些细节中提到过,由于String被设计成immutable,所以才有了StringBuilder和StringBuffer这2个类来帮助我们操作字符串,StringBuilder线程不安全,StringBuffer线程安全,在我们大多数日常使用场景,都是单线程操作字符串,所以StringBuidler用的会多一些,而且编译器也会默认帮我们将+号字符串拼接转化为StringBuidler append,这篇文章我会跟大家分享我知道的StringBuilder使用的一些骚操作。
这个问题只要看下Jdk的源码就能清楚
StringBuilder实现数据结构.png
底层数据结构很简单,就是一个char[] value 和大小字段 count,构造器生成的char[] 默认capacity大小是16,如果很明确插入的字符串很长,应该将capacity设置大一些,避免频繁拷贝数组扩容。
接下来,我们看下StringBuilder 插入删除的实现
StringBuilder insert.png
StringBuilder delete.png
可以看到,由于是基于数组实现的,所以插入删除的效率都不会太高,毕竟都要进行数组的拷贝,但是也不必太过担心,System.arrayCopy的速度还是很快的。
这里我想提一点,append和insert方法都能增长字符串,该如何选择,看上面的源码可以看到,insert不论字符串插入的位置是在中间还是最后,都会进行数组拷贝,而append则会根据当前数组的长度来判断是否需要拷贝扩容,所以如果需要在尾部增加字符串使用append,其他位置使用insert。
我们看一下StringBuilder append方法
StringBuilder 扩容.png
可以看到,在字符数组大小不足够容纳新的字符的时候,会进行扩容,而扩容后的大小是原来数组的大小+新字符串的长度,所以这里的扩容策略是非常保守的,只能够容纳这一次的append操作,所以如果我们要在循环内频繁进行append操作,可以将StringBuilder初始大小capacity设置大一些,避免频繁扩容数组拷贝
平常我们使用的Jdk集合类,如ArrayList,HashMap等都会有clear方法来清空数据,但是StringBuilder没有提供这个方法,那我们如何清空StringBuilder中的数据呢,难道非要循环去调用delete?当然不用,StringBuilder另外给我们提供了setLength方法,参数传0,就达到了清空数据的作用。
StringBuilder 清空.png
通过源码可以看到,setLength方法,当传入的新length小于原来的count时,只是简单的将count设为新length,并不会去动原来的字符数组value,相当于count是一个指针,只是在移动指针,避免了数组拷贝,效率比较高。这个又引出了一个新问题,既然setLength不会去改变value数组,那value占用的内存怎么释放呢?
StringBuilder 提供了trimToSize方法
StringBuiler trim.png
以上(安排的很明白),水平有限,各位大佬轻点喷?