黑马程序员技术交流社区

标题: StringBuffer和StringBuild用起很给力,但是其内部是如何实现的... [打印本页]

作者: 杨鹏    时间: 2012-5-11 00:10
标题: StringBuffer和StringBuild用起很给力,但是其内部是如何实现的...
StringBuffer和StringBuild用起来很给力,但是其内部是如何实现的...看了下API发现两者都实现了Appendalbe接口,IO流中的一些字符输出流也实现了该接口(如:Write,FileWrite,PrintWriter等),所以就想知道Appendalbe有何神奇之处,实现的原理是什么?理解了这个问题估计就知道了字符输出流中要flush()刷新缓冲区的原因。还请大家多指教,谢谢!
作者: 云惟桉    时间: 2012-5-11 00:35
本帖最后由 云惟桉 于 2012-5-11 00:37 编辑

Appendable按照意思理解是可添加的,实现这个接口的类有StringBuffer,StringBuilder,CharBuffer,还有就是Writer
它们都可以具有append操作,我想就是最直接的体现。
需要刷新是因为实现了相应的接口,接口名为Flushable,Writer和OutputStream都实现了它,因此可以刷新。
另外,还有两个接口:
Readable:实现它的类有Read和CharBuffer,Readable 是一个字符源,它有个read方法 int read(CharBuffer cb) ,但是很少用
Closeable:实现它的类有InputStream,OutputStream,Writer,Reader。给IO流赋予可关闭性,是因为需要关闭掉与之相关的系统资源,解除占用。

至于StringBuffer 和 StringBuilder是如何实现的,这里的说明很详细,楼主可以参考一下:
http://www.oschina.net/question/129471_37356

希望能解决楼主的疑惑
作者: 黄秋    时间: 2012-5-11 03:49
真正想了解"内部是如何实现",请看java 的源码,在 %java_home% 的src.zip,如我的在:E:\Program Files\Java\jdk1.6.0_24 下src.zip。src.zip\java\lang 里有StringBuffer.java和StringBuild .java ,当然是很艰深的。

作者: 黄坚声    时间: 2012-5-11 07:35
一个是StringBuffer对象,一个是String对象("abc")
但那个String对象(即:"abc"比较特殊,它是在编译期确定的,所以会放到常量池中,如果在你的程序的其他地方以“显示的方式”出现"abc"的话,那这个"abc",将是同一个"abc")
例如:
StringBuffer A = new StringBuffer("abc");
String str = "abc";
String str2 = "abc";
这3个"abc"其实在编译后的class文件中,指向的是同一内存空间。

下面我来介绍一下StringBuffer类

StringBuffer是一个用于存放动态存放字符串数据的类,他继承自java.lang.AbstractStringBuilder这个类。

所谓动态存放是指:你无需考虑StringBuffer大小的问题。
当你利用StringBuffer的append方法向其自身添加字符串的时候,如果此时StringBuffer默认提供的空间大小不够用,
那么它会自动扩展自身的存储空间,以保证数据能够正常的放入到StringBuffer其中。

我们也可以手动的设置StringBuffer的空间大小
例如:

StringBuffer buf = new StringBuffer(10);

上面的意思是指:将StringBuffer的内部容量设置为10个字符(char)大小的长度。
StringBuffer默认的存储空间大小是16个字符,也就是说 new StringBuffer() 就等于 new StringBuffer(16)。

StringBuffer的底层是利用它的父类(AbstractStringBuilder)内部的一个默认长度为16的字符数组来存放数据的。(即:char value[];)

每当你利用 StringBuffer的append方法向其中添加一个字符串的时候StringBuffer都会调用其父类(AbstractStringBuilder)的append方法,
然后AbstractStringBuilder会判断其内部用于存放数据的那个char[]数组是否已经满了,
(1)如果没有满,就会将你传入的字符串转化为
字符并存入到那个字符数组中(即: str.getChars(0, len, value, count);)。
(2)而如果那个char[]数组已经满了,那么AbstractStringBuilder会创建一个大小为当前数组两倍的新的char[]数组。
然后利用System.arraycopy(value, 0, newValue, 0, count);将原始数据拷贝到这个新的数组中即可。

作者: 黄坚声    时间: 2012-5-11 07:37
看了看StringBuilder的源码,其实现方式与ArrayList的方式是类似的,都是维护了数组。当进行append操作的时候,先检查数组大小是否足够,不够的话需要进行类似ArrayList的扩充容量操作。

想必StringBuilder相对于String类来说,效率高的原因应该是这样的:

String类进行大量的+操作的时候,每次+操作都是需要new一个StringBuilder的,然后使用new出来的StringBuilder进行append操作,append之后,再toString,返回新的String对象给源String对象。记住,toString在源码中是new了String对象的。所以效率低在每次new的StringBuilder和返回时new的String。每次都new大量的这种临时对象,效率自然低很多了。改用StringBuilder的话,每次减少了new操作,而是一直进行append操作。最终需要字符串的时候,再toString。效率高上百倍!






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2