黑马程序员技术交流社区

标题: 关于StringBuilder 容量分配 [打印本页]

作者: 原满    时间: 2013-5-31 11:18
标题: 关于StringBuilder 容量分配
本帖最后由 原满 于 2013-6-1 10:06 编辑

public static void main(String[] args)
        {         
              StringBuilder str=new StringBuilder();
               str.append("hello java");
               System.out.println("str:"+str);
              System.out.println("length:"+str.length());
               System.out.println("capacity:"+str.capacity());
               str.append("hello java");
               System.out.println("str:"+str);
              System.out.println("length:"+str.length());
               System.out.println("capacity:"+str.capacity());         
        }
控制台输出:
str:hello java
length:10
capacity:16
str:hello javahello java
length:20
capacity:34    请问此处为何是34呢?
作者: 娄田田    时间: 2013-5-31 12:08
StringBulider的底层实现是字符数组,如果用默认的构造函数,就会构造一个长度为16的字符数组,也就是此时的capacity为16:
  1. StringBuilder str = new StringBuilder();
  2.                 System.out.println("str:" + str);
  3.                 System.out.println("length:" + str.length());
  4.                 System.out.println("capacity:" + str.capacity());
复制代码
---------------------输出----------------------
str:
length:0
capacity:16
如果构造函数里面用一个字符串参数,那么这个字符数组的长度就是字符串的长度+16,当调用append方法的时候就会判断数组的长度是否足够,长度不够就会重新扩展,扩展的长度为当前数组长度+1再乘以2,这里面说的数组长度指的就是容量
  1. // 使用带有字符串参数的构造方法
  2.                 StringBuilder str = new StringBuilder("hello java");
  3.                 System.out.println("str:" + str);
  4.                 System.out.println("length:" + str.length());
  5.                 // 此时的容量为length+16=26
  6.                 System.out.println("capacity:" + str.capacity());
  7.                
  8.                 str.append("hello java");
  9.                 System.out.println("str:" + str);
  10.                 System.out.println("length:" + str.length());
  11.                 //调用append方法,此时length=20,判断容量是否足够,足够的话容量不变,capacity=26
  12.                 System.out.println("capacity:" + str.capacity());
  13.                
  14.                 str.append("hello java");
  15.                 System.out.println("str:" + str);
  16.                 System.out.println("length:" + str.length());
  17.                 //调用append方法,此时length=30,判断容量是否足够,不够capacity增加为(capacity+1)*2=54
  18.                 System.out.println("capacity:" + str.capacity());
  19.                
  20.                 str.append("hello java");
  21.                 System.out.println("str:" + str);
  22.                 System.out.println("length:" + str.length());
  23.                 //调用append方法,此时length=40,判断容量是否足够,足够的话容量不变,capacity=54
  24.                 System.out.println("capacity:" + str.capacity());
复制代码
---------------------输出-------------------------
str:hello java
length:10
capacity:26
str:hello javahello java
length:20
capacity:26
str:hello javahello javahello java
length:30
capacity:54
str:hello javahello javahello javahello java
length:40
capacity:54
作者: littlefoxtail    时间: 2013-5-31 12:11
StringBuffer的容量不设置初始容量 默认被初始化为16个字符,也就是说缺省容量就是16个字符。
当StringBuffer达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,也就是(2*旧值+2),所以就是34撩
作者: 小羽天空    时间: 2013-5-31 12:41
本帖最后由 小羽天空 于 2013-5-31 12:42 编辑

StringBuilder的append(String s)方法,只要字符串生成器所包含的字符序列s的长度没有超出此容量(原本容量是16个字符),就无需分配新的内部缓冲区。如果内部缓冲区溢出,则此容量自动增大。且增大他之前容量的两倍加2。
作者: 花开花落总相似    时间: 2013-5-31 16:34
本帖最后由 花开花落总相似 于 2013-5-31 16:37 编辑

楼上的都说清楚了 我给你源码 你可以看一下是为什么,对了 我楼上的说是两倍的 应该是IO里面的缓冲区是两倍的  这个StringBuilder 应该不是的
这个是源码 只给你剪到了添加一个StringBuilder的地方有兴趣你可以自己去在拔一下源码

public final class StringBuilder

    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
   
    static final long serialVersionUID = 4383685877147921099L;

    public StringBuilder() {
        super(16);
    }
   
    public StringBuilder(int capacity) {
        super(capacity);
    }

    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
   
    public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }
   private StringBuilder append(StringBuilder sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        int newcount = count + len;
        if (newcount > value.length)
            expandCapacity(newcount);
        sb.getChars(0, len, value, count);
        count = newcount;
        return this;
    }

下面给你贴个流技术的缓冲区自动判断的那个方法 你可以对比一下
private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();
        if (markpos < 0)
            pos = 0;            /* no mark: throw away the buffer */
        else if (pos >= buffer.length)  /* no room left in buffer */
            if (markpos > 0) {  /* can throw away early part of the buffer */
                int sz = pos - markpos;
                System.arraycopy(buffer, markpos, buffer, 0, sz);
                pos = sz;
                markpos = 0;
            } else if (buffer.length >= marklimit) {
                markpos = -1;   /* buffer got too big, invalidate mark */
                pos = 0;        /* drop buffer contents */
            } else {            /* grow buffer */
                int nsz = pos * 2;   
                if (nsz > marklimit)
                    nsz = marklimit;
                byte nbuf[] = new byte[nsz];
                System.arraycopy(buffer, 0, nbuf, 0, pos);
                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                    // Can't replace buf if there was an async close.
                    // Note: This would need to be changed if fill()
                    // is ever made accessible to multiple threads.
                    // But for now, the only way CAS can fail is via close.
                    // assert buf == null;
                    throw new IOException("Stream closed");
                }
                buffer = nbuf;
            }
        count = pos;
        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)
            count = n + pos;
    }






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