从源码层面分析String、StringBuffer、StringBuilder三者的相同点和异同点

面试官:请你讲下String、StringBuffer、StringBuilder的区别;

我:String是不可变的字符序列,底层使用char[]存储;

StringBuffer是可变的字符序列,他是线程安全的,效率低,底层使用char[]存储;

StringBuilder也是可变的字符序列,他是线程不安全的,但是效率高,底层也是使用char[]存储。

面试官:StringBuffer和StringBuilder是如何实现可变的,建对象的时候如何给他们分配空间,插入的时候当空间不足时如何实现扩容。

我:......

回到家的我一气之下打开电脑,从源码层面分析三者的区别。

从JDK1.8的角度分析,String类是final属性的类,而它的构造器也是调用final属性的char数组,这也很好理解为什么String是不可变的。

让我们来看一下StringBuffer和StringBuilder源码

 

 StringBuffer和StringBuilder都共同继承于AbstractStringBuilder抽象类,点开它进去看一下

 AbstractStringBuilder类没有final属性,从它提供的构造器来看,也是直接调用普通的char型数组去构造对象的,因此StringBuffer和StringBuilder是可变的,可变的角度是从该数组本身来讲,在进行添加和删除的操作下并使得该数组本身发生了变化,即是该数组本身可以进行添加和删除操作的。因此也很容易解释StringBuffer和StringBuilder有append方法,而String没有类似的方法。

我们继续来看StringBuffer和StringBuilder的区别

从StringBuffer和StringBuilder两者的构造器可以看出,它们在创建对象的时候可以设置为无参和带参,当设置为无参的时候,StringBuffer和StringBuilder的长度自动赋为16,即将为char[]数组设置16个空间。

那么当需要插入导致数组扩容时,即调用append方法时候,StringBuffer和StringBuilder又做了什么事情呢?

 可见他们同时都是调用父类的append方法,说明两者方法都是同一种操作,这样可以直接看父类AbstractStringBuilder的append方法做了什么

它先是判断了一下插入的字符串是否为空,然后求得插入的字符串的长度,再把当前字符串的长度加上插入的字符串的长度作为参数调用 ensureCapacityInternal方法

 该方法首先把参数和当前数组的空间长度判断了一下看是否容纳的下(大于0表示容纳不下,小于0表示可以容纳),当大于0的时候调用了Arrays的copeOf方法,该方法其实就是把原有的字符串复制到新的数组的字符串上面,值得注意的时该方法中还调用了newCapacity方法

 该方法是把原先数组的空间长度乘于2然后再加2,然后进行判断是否容纳得下全部字符串,等到可以容纳的时候,然后返回一个newCapacity的int类型作为新数组的空间长度。

看到这样,才知道原来append方法插入的方式是这样进行的,总的来说StringBuffer和StringBuilder的扩容方法还挺简单的,而线程安全的观察其实就是StringBuffer使用了同步方法的方式对append实现约束,因为StringBuilder没有,所以StringBuilder的效率是比StringBuffer高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值