<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Oo緣來(lái)是你oO


    posts - 120,comments - 125,trackbacks - 0

    如何讓你的程序運(yùn)行的更快(1)之續(xù)---揭秘StringBuffer的capacity


    馬嘉楠 2006-09-19

    前幾天寫了一篇文章“ 如何讓你的程序運(yùn)行的更快(1)---String VS StringBuffer ”,文章在情景三中提到了如何通過(guò)“設(shè)置StringBuffer的容量來(lái)提升性能”,其中有個(gè)問(wèn)題我沒(méi)有想明白,就是為什么StringBuffer的容量自動(dòng)增加的時(shí)候是“2*舊值+2”呢?

    雖然問(wèn)題依然沒(méi)有解決,不過(guò)也發(fā)現(xiàn)了不少有趣的問(wèn)題,在此和大家分享 。希望能讓你有所收獲,歡迎大家一起討論。

    注:需要用到的函數(shù)說(shuō)明:
    capacity():Returns the current capacity of the String buffer.?
    ?????????????????????The capacity is the amount of storage available for newly inserted characters;??
    ??????????????????????beyond which an allocation will occur.
    length():???Returns the length (character count) of this string buffer.

    ?

    一.StringBuffer的默認(rèn)capacity
    例1:

    StringBuffer?sb? = ? new ?StringBuffer();
    System.out.println( " with?no?characters,?the?initial?capacity?of?StringBuffer?is? " ? +
    ?sb.capacity());
    System.out.println( " and?the?length?of?the?StringBuffer?is? " ? + ?sb.length());

    輸出:

    with?no?characters,?the?initial?capacity?of?StringBuffer?is? 16
    and?the?length?of?the?StringBuffer?is?
    0

    結(jié)論: StringBuffer的默認(rèn)容量(capacity)為16

    原因:
    StringBuffer的默認(rèn)構(gòu)造函數(shù)為

    public ??StringBuffer()?{
    ??????
    this ( 16
    ?);
    }?

    此時(shí)默認(rèn)構(gòu)造函數(shù)又調(diào)用了StringBuffer的代參數(shù)的構(gòu)造函數(shù),設(shè)置字符串?dāng)?shù)組value長(zhǎng)度為16,如下:

    private ? char ?value[];??????????????? //The?value?is?used?for?character?storage.
    private ? boolean ?shared;???????? // A?flag?indicating?whether?the?buffer?is?shared

    public ?StringBuffer( int ?length)?{
    ??????value?
    = ? new ? char
    [length];
    ??????shared?
    = ? false
    ;
    }
    ?
    // 調(diào)用capacity()返回字符串?dāng)?shù)組value的長(zhǎng)度,即StringBuffer的容量(capacity)

    public ? synchronized ? int ?capacity()?{
    ??????return
    ?value.length;
    }



    二.用字符串初始化StringBuffer的內(nèi)容

    在聲明一個(gè)StringBuffer變量的時(shí)候,用字符串進(jìn)行初始化,容量會(huì)有變化么?

    例2:

    // 聲明并初始化
    StringBuffer?sb1? = ? new ?StringBuffer( " hello?world " ?);
    System.out.println(
    " with?characters,?the?capacity?of?StringBuffer?is? " ? +
    ??sb1.capacity());
    System.out.println(
    " but?the?length?of?the?StringBuffer?is? " ? +
    ?sb1.length());?

    // 利用append()來(lái)設(shè)置StringBuffer的內(nèi)容

    StringBuffer?sb11? = ? new ?StringBuffer();
    sb11.append(
    " hello?world "
    );
    System.out.println(
    " with?append(),?the?capacity?of?StringBuffer?is? " ? +
    ?sb11.capacity());
    System.out.println(
    " but?the?length?of?the?StringBuffer?is? " ? + ?sb11.length());


    兩者輸出結(jié)果會(huì)一樣么?
    你一定認(rèn)為,這不是顯然的么。用長(zhǎng)度為11的字符串“hello world”進(jìn)行初始化,其長(zhǎng)度11小于StringBuffer的默認(rèn)容量16。所以兩者結(jié)果都為capacity=16,length=11。
    那么實(shí)際結(jié)果如何呢?

    輸出:

    with characters, the capacity of StringBuffer is 27
    but the length of the StringBuffer is 11
    with append(), the capacity of StringBuffer is 16
    but the length of the StringBuffer is 11

    疑問(wèn):
    怎么第一種方法的StringBuffer的capacity是27(16+11)呢?

    原因:
    StringBuffer的帶參數(shù)的構(gòu)造函數(shù)

    1?public ?StringBuffer(String?str)?{
    2???????this(str.length()?+?16
    );
    3???????
    append(str);
    4?}

    結(jié)論:
    StringBuffer的capacity等于用來(lái)初始化的字符串長(zhǎng)度(11)加上StringBuffer的默認(rèn)容量(16),而不是我們想當(dāng)然的在默認(rèn)容量16中拿出11個(gè)來(lái)存放字符串“hello world”。
    如果我們不設(shè)置StringBuffer的capacity,分別對(duì)兩者繼續(xù)追加字符串,任其自動(dòng)增長(zhǎng),其容量增長(zhǎng)如下:
    第一種情況:27,56,114,230,462,926...,
    第二種情況:16,34,70? ,142,286,574...,
    (為什么容量增加會(huì)是這種規(guī)律,后面會(huì)做解釋)。

    我想情況2節(jié)省空間的概率大一些,因?yàn)镾tringBuffer的capacity的增長(zhǎng)比情況1慢,每次增加的空間小一些。
    所以以后寫代碼的時(shí)候可以考慮使用第二種方法(使用StringBuffer的append()),特別是初始化字符串很長(zhǎng)的情況。當(dāng)然這會(huì)多寫一行代碼^+^:


    三.StringBuffer的capacity變化

    例3:

    StringBuffer?sb3? = ? new ?StringBuffer();
    for ( int ?i = 0 ;?i < 12 ;?i ++
    ){
    ??????sb3.append(i);
    }
    System.out.println(
    " before?changed,?the?capacity?is? " ? +
    ?sb3.capacity());
    System.out.println(
    " and?the?length?is? " ? +
    ?sb3.length());?

    for ( int ?i = 0 ;?i < 10 ;?i ++
    ){
    ??????sb3.append(i);
    }
    System.out.println(
    " first?time?increased,?the?capacity?is? " ? +
    ?sb3.capacity());
    System.out.println(
    " and?the?length?is? " ? +
    ?sb3.length());?

    for ( int ?i = 0 ;?i < 11 ;?i ++
    ){
    ??????sb3.append(i);
    }
    System.out.println(
    " second?time?increased,?the?capacity?is? " ? +
    ?sb3.capacity());
    System.out.println(
    " and?the?length?is? " ? +
    ?sb3.length());?

    輸出:

    before?changed,?the?capacity?is? 16
    and?the?length?is?
    14
    first?time?increased,?the?capacity?is?
    34
    and?the?length?is?
    24
    second?time?increased,?the?capacity?is?
    70
    and?the?length?is?
    36 ?

    奇怪,benfore changed怎么長(zhǎng)度不是12而是14呢?哈哈,開(kāi)始我也困惑了一下,仔細(xì)想想就會(huì)明白的,你可以輸出sb3看看System.out.println("the content of sb3 is " + sb3.toString());

    結(jié)論:
    capacity增長(zhǎng)的規(guī)律為 (舊值+1)*2

    原因:
    StringBuffer的容量增加函數(shù)expandCapacity():

    private ? void ?expandCapacity( int ?minimumCapacity)?{
    int ?newCapacity? = ?(value.length? + ? 1 )? * ? 2
    ;
    if ?(newCapacity? < ? 0
    )?{
    ??????newCapacity?
    =
    ?Integer.MAX_VALUE;
    }?
    else ? if ?(minimumCapacity? >
    ?newCapacity)?{
    ??????newCapacity?
    =
    ?minimumCapacity;
    }
    ?
    char ?newValue[]? = ? new ? char
    [newCapacity];
    System.arraycopy(value,?
    0 ,?newValue,? 0
    ,?count);
    value?
    =
    ?newValue;
    shared?
    = ? false
    ;
    }?

    疑問(wèn):
    為什么要(舊值+1)*2呢?

    我自己的想法:
    也許是考慮到value.length的值可能為0(初始化時(shí)設(shè)置StringBuffer的capactity為0).
    或者考慮到溢出的情況?
    但是可能是JVM的某些限制,我的機(jī)器數(shù)組最大可以設(shè)置為30931306,再大就報(bào)錯(cuò):
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    30931306這個(gè)數(shù)字好奇怪

    還有哪方面的考慮么?誰(shuí)知道,能告訴我么?


    四.StringBuffer的capacity只能大不能小

    例5:

    ?1?StringBuffer?sb4?=?new ?StringBuffer();
    ?2?System.out.println("before?ensureCapacity(),?the?capacity?is?"?+
    ?sb4.capacity());
    ?3?sb4.ensureCapacity(10
    );
    ?4?System.out.println("after?ensureCapacity(10),?the?capacity?is?"?+
    ?sb4.capacity());
    ?5?
    ????????
    ?6?System.out.print("now,?the?capacity?is?"?+?sb4.capacity()?+?",?"
    );
    ?7?sb4.ensureCapacity(20
    );
    ?8?System.out.println("after?ensureCapacity(20),?the?capacity?is?"?+
    ?sb4.capacity());
    ?9?
    ????????
    10?System.out.print("now,?the?capacity?is?"?+?sb4.capacity()?+?",?"
    );
    11?sb4.ensureCapacity(80
    );
    12?System.out.println("after?ensureCapacity(80),?the?capacity?is?"?+?sb4.capacity());

    輸出:

    before?ensureCapacity(),?the?capacity?is? 16
    after?ensureCapacity(
    10 ),?the?capacity?is? 16
    now,?the?capacity?is?
    16 ,?after?ensureCapacity( 20 ),?the?capacity?is? 34
    now,?the?capacity?is?
    34 ,?after?ensureCapacity( 80 ),?the?capacity?is? 80

    結(jié)論:
    當(dāng)設(shè)置StringBuffer的容量
    1、小于當(dāng)前容量時(shí),容量不變。
    ??????本例中,容量依然為16。
    2、大于當(dāng)前容量,并且小于(當(dāng)前容量+1)*2,則容量變?yōu)?當(dāng)前容量+1)*2。
    ??????本例中,16<20<(16+1)*2=34,所以容量為34。
    3、大于當(dāng)前容量,并且大于(當(dāng)前容量+1)*2,則容量變?yōu)橛脩羲O(shè)置的容量。
    ??????本例中,80>16,80>(16+1)*2=34,所以容量為80。

    原因:
    函數(shù):ensureCapacity( )和 expandCapacity( )進(jìn)行了控制

    public ? synchronized ? void ?ensureCapacity( int ?minimumCapacity)?{
    ??????
    if ?(minimumCapacity? >
    ?value.length)?{
    // 當(dāng)設(shè)置StringBuffer的容量小于當(dāng)前容量時(shí),容量不變。

    ????????????expandCapacity(minimumCapacity);
    ??????}
    }

    private ? void ?expandCapacity( int
    ?minimumCapacity)?{
    ??????int ?newCapacity? = ?(value.length? + ? 1 )? * ? 2
    ;
    ??????if ?(newCapacity? < ? 0
    )?{
    ????????????newCapacity?
    =
    ?Integer.MAX_VALUE;
    ??????}?
    else ? if ?(minimumCapacity? >
    ?newCapacity)?{
    ??????//
    當(dāng)設(shè)置StringBuffer的容量大于(當(dāng)前容量+1)*2,則容量變?yōu)橛脩羲O(shè)置的容量。
    ??????// 否則,容量為(當(dāng)前容量+1)*2,即newCapacity

    ????????????newCapacity? = ?minimumCapacity;
    ??????}
    ?
    char ?newValue[]? = ? new ? char
    [newCapacity];
    System.arraycopy(value,?
    0 ,?newValue,? 0
    ,?count);
    value?
    =
    ?newValue;
    shared?
    = ? false
    ;
    }?


    ?
    注:
    問(wèn)一下
    String str = String.valueOf(null);
    System.out.println(str.length());

    你們執(zhí)行的話會(huì)出錯(cuò)么?
    我的報(bào)錯(cuò),我的是jdk1.4

    因?yàn)镾tringBuffer中的append(String str)函數(shù)中有這樣的語(yǔ)句,

    public ? synchronized ?StringBuffer?append(String?str)?{
    if ?(str? == ? null
    )?{
    ??????str?
    =
    ?String.valueOf(str);
    }

    int ?len? = ?str.length(); // len有可能得負(fù)值么?

    int ?newcount? = ?count? + ?len;
    if ?(newcount? >
    ?value.length)
    expandCapacity(newcount);
    str.getChars(
    0
    ,?len,?value,?count);
    count?
    =
    ?newcount;
    return ? this
    ;
    }

    ?



    馬嘉楠
    jianan.ma@gmail.com

    posted on 2006-09-20 17:05 馬嘉楠 閱讀(2470) 評(píng)論(5)  編輯  收藏

    FeedBack:
    # re: 如何讓你的程序運(yùn)行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:17 | 肉包
    String str = String.valueOf(null);
    -- >
    String str = String.valueOf((Object)null);
      回復(fù)  更多評(píng)論
      
    # re: 如何讓你的程序運(yùn)行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:43 | 肉包
    JDK1.5
    String.valueOf(null)失敗  回復(fù)  更多評(píng)論
      
    # re: 如何讓你的程序運(yùn)行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:49 | 肉包
    是StringBuffer append方法,和String valueOf有關(guān)系么
    -.-"  回復(fù)  更多評(píng)論
      
    # re: 如何讓你的程序運(yùn)行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:56 | 肉包
    System.out.println(null instanceof Object); //false
    StringBuffer str = new StringBuffer().append((StringBuffer)null); //pass
    StringBuffer str1 = new StringBuffer().append((String)null); //pass
    StringBuffer str1 = new StringBuffer().append(null); //throw exception
    System.out.println(String.valueOf((Object)null).length()); //4  回復(fù)  更多評(píng)論
      
    # re: 如何讓你的程序運(yùn)行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2012-04-10 10:31 | KingOfLightArmy
    public synchronized StringBuffer append(String str) {
    if (str == null ) {
    str = String.valueOf(str);
    }

    int len = str.length(); // len有可能得負(fù)值么?
    int newcount = count + len;
    if (newcount > value.length)
    expandCapacity(newcount);
    str.getChars( 0 , len, value, count);
    count = newcount;
    return this ;
    }
    上面的 str = String.valueOf(str);沒(méi)有問(wèn)題,原因在于,即使str是null,這個(gè)null是(String)null,本質(zhì)是String.valueOf((String)null),所以不會(huì)出現(xiàn)異常。這和 String.valueOf(null),是有區(qū)別的,因?yàn)閚ull不屬于任何類型,所以valueOf這個(gè)有多個(gè)重載方法,但是都無(wú)法匹配null,除非轉(zhuǎn)型(Object)null。  回復(fù)  更多評(píng)論
      

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 久久久久亚洲Av片无码v| 我要看免费的毛片| XXX2高清在线观看免费视频| 羞羞视频免费网站含羞草| 久久精品国产亚洲AV| 亚洲欧美aⅴ在线资源| 国产成人亚洲综合网站不卡| 99久久久国产精品免费牛牛四川| 成人免费乱码大片A毛片| 中文字幕a∨在线乱码免费看| 国产免费高清69式视频在线观看| 一级做a爰片久久毛片免费陪| 一边摸一边桶一边脱免费视频 | 国产免费私拍一区二区三区| 在线免费一区二区| 国产成人精品男人免费| 国产在线观看免费不卡| 亚洲成av人片不卡无码久久| 亚洲综合在线另类色区奇米| 亚洲av永久无码制服河南实里| 亚洲精品第五页中文字幕| 亚洲中文字幕人成乱码| 亚洲欧美日韩中文二区| 黄床大片30分钟免费看| 9久热精品免费观看视频| 一级毛片**不卡免费播| 国产一卡2卡3卡4卡2021免费观看 国产一卡2卡3卡4卡无卡免费视频 | 无码少妇一区二区浪潮免费| 大学生a级毛片免费观看| 日本特黄特色aa大片免费| 亚洲成a人片在线观看日本麻豆| 亚洲午夜久久久久妓女影院 | 亚洲国产高清在线一区二区三区| 久久久久亚洲精品男人的天堂| 亚洲av永久无码精品秋霞电影影院| 亚洲网址在线观看| 亚洲精品伦理熟女国产一区二区| 特黄aa级毛片免费视频播放| 国产啪精品视频网站免费尤物| 国产成人精品免费视频大| 国产gav成人免费播放视频|