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

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

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

    Oo緣來是你oO


    posts - 120,comments - 125,trackbacks - 0

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


    馬嘉楠 2006-09-19

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

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

    注:需要用到的函數(shù)說明:
    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的默認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的默認容量(capacity)為16

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

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

    此時默認構(gòu)造函數(shù)又調(diào)用了StringBuffer的代參數(shù)的構(gòu)造函數(shù),設(shè)置字符串數(shù)組value長度為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()返回字符串數(shù)組value的長度,即StringBuffer的容量(capacity)

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



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

    在聲明一個StringBuffer變量的時候,用字符串進行初始化,容量會有變化么?

    例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()來設(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é)果會一樣么?
    你一定認為,這不是顯然的么。用長度為11的字符串“hello world”進行初始化,其長度11小于StringBuffer的默認容量16。所以兩者結(jié)果都為capacity=16,length=11。
    那么實際結(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

    疑問:
    怎么第一種方法的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等于用來初始化的字符串長度(11)加上StringBuffer的默認容量(16),而不是我們想當然的在默認容量16中拿出11個來存放字符串“hello world”。
    如果我們不設(shè)置StringBuffer的capacity,分別對兩者繼續(xù)追加字符串,任其自動增長,其容量增長如下:
    第一種情況:27,56,114,230,462,926...,
    第二種情況:16,34,70? ,142,286,574...,
    (為什么容量增加會是這種規(guī)律,后面會做解釋)。

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


    三.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怎么長度不是12而是14呢?哈哈,開始我也困惑了一下,仔細想想就會明白的,你可以輸出sb3看看System.out.println("the content of sb3 is " + sb3.toString());

    結(jié)論:
    capacity增長的規(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
    ;
    }?

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

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

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

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


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

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

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

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

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

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


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

    你們執(zhí)行的話會出錯么?
    我的報錯,我的是jdk1.4

    因為StringBuffer中的append(String str)函數(shù)中有這樣的語句,

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

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

    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 馬嘉楠 閱讀(2484) 評論(5)  編輯  收藏

    FeedBack:
    # re: 如何讓你的程序運行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:17 | 肉包
    String str = String.valueOf(null);
    -- >
    String str = String.valueOf((Object)null);
      回復  更多評論
      
    # re: 如何讓你的程序運行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:43 | 肉包
    JDK1.5
    String.valueOf(null)失敗  回復  更多評論
      
    # re: 如何讓你的程序運行的更快(1)之續(xù)---揭秘StringBuffer的capacity
    2006-09-29 14:49 | 肉包
    是StringBuffer append方法,和String valueOf有關(guān)系么
    -.-"  回復  更多評論
      
    # re: 如何讓你的程序運行的更快(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  回復  更多評論
      
    # re: 如何讓你的程序運行的更快(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有可能得負值么?
    int newcount = count + len;
    if (newcount > value.length)
    expandCapacity(newcount);
    str.getChars( 0 , len, value, count);
    count = newcount;
    return this ;
    }
    上面的 str = String.valueOf(str);沒有問題,原因在于,即使str是null,這個null是(String)null,本質(zhì)是String.valueOf((String)null),所以不會出現(xiàn)異常。這和 String.valueOf(null),是有區(qū)別的,因為null不屬于任何類型,所以valueOf這個有多個重載方法,但是都無法匹配null,除非轉(zhuǎn)型(Object)null。  回復  更多評論
      

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


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 亚洲不卡1卡2卡三卡2021麻豆| 亚洲av永久无码精品秋霞电影秋 | 亚洲日韩国产精品无码av| 亚洲人成网站18禁止一区| A级毛片高清免费视频在线播放| 亚洲日本国产乱码va在线观看| 日本免费一区二区三区最新| 国产日韩久久免费影院| 亚洲女人18毛片水真多| 亚洲国产成人VA在线观看| 久久ww精品w免费人成| 成a人片亚洲日本久久| 亚洲精品在线网站| 国产一级高清视频免费看| 无码av免费一区二区三区| 亚洲综合伊人久久综合| 成年人在线免费观看| a级毛片毛片免费观看久潮喷| 亚洲人成电影网站| 中文字幕第13亚洲另类| 在线观看免费毛片| 鲁丝片一区二区三区免费| 国产成人亚洲精品91专区高清| 亚洲国产成人精品不卡青青草原| 日本高清色本免费现在观看| 一级毛片免费观看| 一级做α爱过程免费视频| 亚洲综合伊人制服丝袜美腿| 亚洲国产精品一区二区成人片国内| 免费看AV毛片一区二区三区| 嫩草在线视频www免费观看| 美女视频黄a视频全免费网站色 | 国产黄色免费网站| 国产做国产爱免费视频| 亚洲av成人一区二区三区在线播放| 精品亚洲成AV人在线观看| 国产午夜亚洲精品午夜鲁丝片 | 亚洲午夜福利AV一区二区无码| 最新中文字幕免费视频| 91免费国产精品| a级毛片毛片免费观看久潮|