数据结构分析
StringBuffer继承自AbstractStringBuilder,数据的存储方式定义在此类中。
在AbstractStringBuilder类中维护了一个名为value,类型为char数组的成员变量用来储存数据。
可以看到初始化StringBuffer类对象时会默认为其分配16个字符的存储空间。
然后触发父类AbstractStringBuilder的构造函数,对用来储存数据的这个char数组进行初始化。
通过被定义在父类中的append()方法向char数组中存入数据:
对String数据的处理
以append(String)方法为例,向其中拼接进一条新的数据:
看看append(String)方法内部会做哪些处理:
会去调用StringBuffer的父类AbstractStringBuilder#append(java.lang.String)方法:
看看java.lang.String#getChars(int, int, char[], int)这个方法是用来做什么的:
这个方法的作用是将一个String对象中维护的char数组copy进指定的另一个char数组中,而这个char数组就是父类AbstractStringBuilder中维护的那个名为value的char数组。
那如果存入的数据类型不能直接被转为char类型,又会怎样被存入到这个数组中呢?
对boolean数据的处理
我们append一个布尔值看看:
看看处理的流程:
这段代码是将boolean类型的数据存入StringBuffer对象的关键代码。
在这段代码中会直接将boolean值对应的字符表示转为一个个字符,比如boolean=true,那么这个boolean值对应的字符表示就是’true’。
count表示的是存放的字符数组当前的总数,value[count++]代表的逻辑是将每个字符按顺序放进char数组的最后一个位置上。
对double数据的处理
最后再看一个append进一个double类型数据的情况:
调用getBinaryToASCIIConverter(double)方法,会将double数据转为字符数组,比如1.3,就变成了[‘1’,‘3’],然后封装进FloatingDecimal.BinaryToASCIIConverte类实例,最后调用这个类实例将[‘1’,‘3’]append进StringBuffer实例的value数组中。我们进入BinaryToASCIIConverte#appendTo(Appendable)方法的内部看看:
在这里会通过调用StringBuffer实例的append(char[], int, int)方法,将基于double数据转成的字符数组存入到StringBuffer实例中。
我们看看这个this.buffer是什么。
这个属性来自BinaryToASCIIConverte类对象,它是这么被定义的:
我们debug看一下这个属性里面会存放哪些数据:
可知这个字段存放的是基于double数据转成的字符数组。
了解完this.buffer后,我们现在再看看这个维护在StringBuffer实例的append(char[], int, int)方法:
可以看到StringBuffer#append(char[], int, int)方法回去调用以下这个方法:
通过执行System.arraycopy()方法,将char类型数组中的数据copy进StingBuffer实例中的value数组中。直到这里,double数据就被存入到StingBuffer实例中了。
最后我们测试一下,通过append进String数据、boolean数据、double数据,这个StringBuffer实例中存放的数据会怎样变化:
输出结果:testfalse1.35
看看内部的变化过程:
第一次sppend进一个String字符串:test
第二次append boolean:false
第三次append double:1.35
总结
- StringBuffer内部维护了一个类型为char、名为value的数组。所有append进StringBuffer实例的数据,都会被存放到这个数组里。这个数组是StringBuffer实例用来存放数据的。
- 不管append进哪种类型的数据,比如double或boolean,最后都会被转化为对应的字符,比如1.3,append进StringBuffer实例后数据的表现形式为’1.3’。