黑马程序员技术交流社区

标题: StringBuffer的问题 [打印本页]

作者: 火之意志    时间: 2013-5-22 23:15
标题: StringBuffer的问题
本帖最后由 火之意志 于 2013-5-23 13:21 编辑

StringBuffer buffer=new StringBuffer();
        buffer.append("HelloWorld!");
        buffer.insert(5,buffer);
        System.out.println(buffer);

        结果为什么会是:HelloHelloHelloHe World!而不是HelloHello World World! ?
ps:通过试验,只要不是buffer对象,其他类型的对象都可以用insert方法插入
作者: 刘学明       时间: 2013-5-23 00:48
这个不知道 盲点 看别人回答
作者: 刘治广    时间: 2013-5-23 09:03
因为当你在(5,buffer)这个位置插入的时候 buffer是改变的,所有会不断的在第五个位置插入
作者: 史政法    时间: 2013-5-23 09:26
楼上说的貌似靠谱,,,,但是具体的插入过程呢?????
作者: hdsjsql    时间: 2013-5-23 09:54
同求具体过程
作者: 刘治广    时间: 2013-5-23 09:55
因为buffer是同一个区域。一旦,这个区域添加了一个元素,那么,整个区域就是变化的。
        结果就不可预料
作者: 张世威    时间: 2013-5-23 10:24
1、通过断点调试,发现buffer.insert(5,buffer) 这个方法的插入逻辑如下图
   
2,关键点在于buffer1.insert(5,buffer2)是取一个字符再插入一个字符,当buffer1和buffer2不一样,这个自然不会有问题。
当buffer1==buffer2,后面取的字符可能是前面刚插入进去的,而不是原始需要插入的字符。
它只记字符索引值,这样就会出错。
3、看来源码里面还是有bug的。。。应该先把buffer2的字符放到temp里面,谁能想到,经过这么长的迭代,
会有value==s?关键位置源码
for (int i=start; i<end; i++)
            value[dstOffset++] = s.charAt(i);
//AbstractStringBuilder的1115-1116行。
   
作者: student    时间: 2013-5-23 10:41
这里,源和目的都是StringBuffer的实例对象buffer,在插入元素的过程中,buffer在不断变化,也就是说源和目的在不断地变化,变化的过程如下。
调用insert之前,buffer的值为“HelloWorld!”,insert调用过程就是将源转换成字符数组,然后将字符数组中的每一个元素插入到目的中,步骤如下:


注意,数据源和数据目的都在变化

1. 将数据源HelloWorld!的第1位置元素H插入到buffer的第5个位置(下标从0开始,下面相同,buffer的值变成HelloHWorld!;
2. 将数据源HelloHWorld!的第2
位置元素e插入到buffer的第6个位置,buffer的值变成HelloHeWorld!;
3. 将数据源HelloHeWorld!的第3
位置元素l插入到buffer的第7个位置,buffer的值变成HelloHelWorld!;
4. 将数据源
HelloHelWorld!的第4位置元素l插入到buffer的第8个位置,buffer的值变成HelloHellWorld!;
5. 将数据源
HelloHellWorld!的第5位置元素o插入到buffer的第9个位置,buffer的值变成HelloHelloWorld!;

注意,下面开始有变化了,这种变化是因为数据源和数据目都是同一个StringBuffer对象的引用buffer造成的

6. 将数据源HelloHelloWorld!的第6位置元素H插入到buffer的第10个位置,buffer的值变成HelloHelloHWorld!;
7. 将数据源HelloHelloHWorld!的第7位置元素e插入到buffer的第11个位置,buffer的值变成HelloHelloHeWorld!;
8. 将数据源HelloHelloHeWorld!的第8位置元素l插入到buffer的第12个位置,buffer的值变成HelloHelloHelWorld!;
9. 将数据源HelloHelloHelWorld!的第9位置元素l插入到buffer的第13个位置,buffer的值变成HelloHelloHellWorld!;
10. 将数据源HelloHelloHellWorld!的第10位置元素o插入到buffer的第14个位置,buffer的值变成HelloHelloHelloWorld!;
11. 将数据源HelloHelloHelloWorld!的第11位置元素H插入到buffer的第15个位置,buffer的值变成HelloHelloHelloHWorld!;

之所以执行11次将字符数组中的元素插入到buffer中,是因为原来的buffer的值“HelloWorld!”长度为11。



作者: 无妄无涯    时间: 2013-5-23 11:08
本帖最后由 无妄无涯 于 2013-5-23 12:09 编辑

由你的结果得出字符串应该是“Hello World”,即中间有空格。源字符串和目的字符串都是buffer,根据你的方式,buffer中的内容在不断变化。由于要加入的字符串“Hello World!”长12,因此在执行插入时会给buffer增加12字节的长度,然后从索引5处开始插入,直到24字节长度占满。过程是这样:


如果想完成要求的效果可以这样:
  1. class Test {
  2.         public static void main(String[] args) {
  3.                
  4.                 StringBuffer buffer=new StringBuffer();
  5.                 StringBuffer buffer1=new StringBuffer();
  6.         buffer.append("HelloWorld!");
  7.         buffer1.append("Hello World!");
  8.         buffer.insert(5,buffer1);
  9.         System.out.println(buffer);
  10.         }
  11. }
复制代码

作者: Miss小强    时间: 2013-5-23 12:19
这个bug太吓人了。。。
为什么不这样做呢?
buffer.(5,buffer.toString);
作者: Miss小强    时间: 2013-5-23 12:24
这个题目确实有意思:
但是如果说如果源代码中使用final关键字就不会出现这种问题了
从设计思想上说,即封装性;
你给我传递的参数是不允许改变的;

作者: 火之意志    时间: 2013-5-23 13:19
恩,大神们说的有道理,我自己也试验了,只要不是StringBuffer的对象,调用insert()方法都可以通过,唯独不能自己插入自己,既buffer。insert(3,buffer)是错误的,其他类型的对象都可以
作者: 张世威    时间: 2013-5-23 13:48
设置一断点,跟着程序走,就可以知道inser()方法里面是怎么插入的。




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