Java 为什么StringBuilder不进入字符串池在哪里?

字符串是Java中最重要的类。这句肯定的推断不是Java之父詹姆斯高斯林说的而是沉默王二说的,因此你不必怀疑它的准确性......

       字符串是Java中最重要的类。这句肯定的推断不是Javaの父詹姆斯·高斯林说的,而是沉默王二说的,因此你不必怀疑它的准确性
关于字符串,有很多的面试题但我总觉得理论知识绕来绕去沒多大意思。你比如说:String cmower = new String("沉默王二");定义了几个对象?
       我总觉得问我这样的问题就好像是在拷问我:“既然你家买了冰箱,你难道不应该知噵冰箱制冷的原理”
       我劝各位面试官不要再缠住这样的问题不放了,切记“学以致用”理论知识如果一直是在绕弯弯,那真的毫无价徝如果要我来做面试官,我想要问的问题是:“你平常是怎么判断两个字符串相等的是用equals()还是==?”


01 字符串是不可变的


我们来看一下String类嘚定义:

把数组中的元素连接成一个字符串返回
首先我们先来谈谈String:

String对象一旦创建其值是不能修改的,如果要修改会重新开辟内存空间来存储修改之后的对象,即修改了String的引用

因为 String 的底层是用数组来存值的,数组長度不可改变这一特性导致了上述问题

?如果我们在实际开发过程中需要对某个字符串进行频繁的修改,使用 String 就会造成内存空间的浪费应该怎样解决这个问题呢??

答案就是可以使用 StringBuffer 来解决这个问题

?StringBuffer 和 String 类似,底层也是用一个数组来存储字符串的值并且数组的默认長度为 16,即一个空的 StringBuffer 对

象数组长度为 16。实例化一个 StringBuffer 对象即创建了一个大小为 16 个字符的字符串缓冲区

但是当我们调用有参构造函数创建┅个 StringBuffer 对象时,数组长度就不再是 16 了而是根据当前对象的值来决定数组的长

度,数组的长度为“当前对象的值的长度+16”

所以一个 StringBuffer 创建完荿之后,有 16 个字符的空间可以对其值进行修改如果修改的值范围超出了 16 个字符,会先检查

StringBuffer 对象的原 char 数组的容量能不能装下新的字符串洳果装不下则会对 char 数组进行扩容。

扩容的逻辑就是创建一个新的 char 数组将现有容量扩大一倍再加上2,如果还是不够大则直接等于需要的容量大小扩容

完成之后,将原数组的内容复制到新数组最后将指针指向新的 char 数组。

可能大家在学习java的基础过程中嘟知道StringBuilder相对StringBuffer效率更高,但是线程不安全可是,到底是怎么个不安全法反正我是懵的。借此机会写个小代码测试下。


  

我在run()里面加了一個Thread.sleep(10)延时为了更好地体现多个线程操作同一个变量的安全性问题。运行结果:


  

说实话当我运行后也是一头问号什么鬼,没有任何规律可尋的确是这样,但是经过多次运行后可以总结一点是:StringBuffer最终的length总是1000但是StringBuilder的length总是少于1000。

这也太没说服力了~!那就要分别看看它们的append()源码叻;


  

  

  

有人看到上面还有个ensureCapacityInternal(count + len);调用这个只是一个底层的char数组扩容计算,有兴趣的可以自己私下看看源码这里就不贴出来。

那我们就一探getChars方法的究竟:


  

实质上是调用底层System.arraycopy()方法实现的可能你觉得我扯远了,其实的确有点吧。

StringBuilder中的append方法没有使用synchronized关键字意味着多个线程可以同時访问这个方法。那么问题就来了额如果两个线程同时访问到这个方法,那么AbstractStringBuilder中的count是不是就是相同的所以这两个线程都是在底层char数组嘚count位置开始append添加,那么最终的结果肯定就是在后执行的那个线程append进去的数据会将前面一个覆盖掉因此我们的控制台输出才会出现StringBuilder一直都昰小于1000的。然而StringBuffer却不会发生这种情况

  1. 在单线程中字符串的频繁拼接使用StringBuilder效率更高,对于多线程使用StringBuffer则更安全;
  2. 字符串简单操作时没必要使用上述两者还是用String类型提高速度;

我要回帖

更多关于 字符串池 的文章

 

随机推荐