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

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

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

    honzeland

    記錄點滴。。。

    常用鏈接

    統計

    Famous Websites

    Java

    Linux

    P2P

    最新評論

    String和StringBuffer之概覽

    String StringBuffer 之概覽
      非可變對象一旦創建之后就不能再被改變,可變對象則可以在創建之后被改變。 String 對象是非可變對象, StringBuffer 對象則是可變對象。為獲得更佳的性能你需要根據實際情況小心謹慎地選擇到底使用這兩者中的某一個。下面的話題會作詳細的闡述。(注意:這個章節假設讀者已經具備 Java String StringBuffer 的相關基礎知識。)
    ?
    創建字符串的較佳途徑
    你可以按照以下方式創建字符串對象:
    1.?String?s1?=?"hello";?
    ????String?s2?=?"hello";?
    2.?String?s3?=?new?String("hello");
    ????String?s4?=?new?String("hello");
    ?
    上面哪種方式會帶來更好的性能呢?下面的代碼片斷用來測量二者之間的區別。

    StringTest1.java
    package?com.performance.string;
    /**?This?class?shows?the?time?taken?for?creation?of
    ?*??String?literals?and?String?objects.
    ?*/
    public?class?StringTest1?{
    public?static?void?main(String[]?args){
    ????//?create?String?literals
    ????long?startTime?=?System.currentTimeMillis();
    ????for(int?i=0;i<50000;i++){
    ????String?s1?=?"hello";
    ????String?s2?=?"hello";
    ????}
    ????long?endTime?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?creation?of?String?literals?:?"
    ??????????????????+?(endTime?-?startTime)?+?"?milli?seconds"?);
    ????//?create?String?objects?using?'new'?keyword???????
    ????long?startTime1?=?System.currentTimeMillis();
    ????for(int?i=0;i<50000;i++){
    ????String?s3?=?new?String("hello");
    ????String?s4?=?new?String("hello");
    ????}
    ????long?endTime1?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?creation?of?String?objects?:?"
    ??????????????????+?(endTime1?-?startTime1)+"?milli?seconds");
    ????}
    }
    這段代碼的輸出:
    Time?taken?for?creation?of?String?literals?:?0?milli?seconds
    Time?taken?for?creation?of?String?objects?:?170?milli?seconds
    ?
    JVM
    是怎樣處理字符串的呢?
       Java 虛擬機會維護一個內部的滯留字符串對象的列表(唯一字符串的池)來避免在堆內存中產生重復的 String 對象。當 JVM class 文件里加載字符串字面量并執行的時候,它會先檢查一下當前的字符串是否已經存在于滯留字符串列表,如果已經存在,那就不會再創建一個新的 String 對象而是將引用指向已經存在的 String 對象, JVM 會在內部為字符串字面量作這種檢查,但并不會為通過 new 關鍵字創建的 String 對象作這種檢查。當然你可以明確地使用 String.intern() 方法強制 JVM 為通過 ?new 關鍵字創建的 String 對象作這樣的檢查。這樣可以強制 JVM 檢查內部列表而使用已有的 String 對象。
      所以結論是, JVM 會內在地為字符串字面量維護一些唯一的 String 對象,程序員不需要為字符串字面量而發愁,但是可能會被一些通過 ?new 關鍵字創建的 String 對象而困擾,不過他們可以使用 intern() 方法來避免在堆內存上創建重復的 String 對象來改善 Java 的運行性能。下一小節會向大家展示更多的信息。
    ?
    下圖展示了未使用 intern() 方法來創建字符串的情況。
    ?
    string_creating_without_intern()?method
      你可以自己使用 == 操作符和 String.equals() 方法來編碼測試上面提到的區別。 == 操作符會返回 true 如果一些引用指向一個相同的對象但不會判斷 String 對象的內容是否相同; String.equals() 方法會返回 true 如果被操作的 String 對象的內容相同。對于上面的代碼會有 s1==s2 ,因為 s1 s2 兩個引用指向同一個對象,對于上面的代碼, s3.equals(s4) 會返回 true 因為兩個對象的內容都一樣為 ”hello” 。你可以從上圖看出這種機制。在這里有三個獨立的包含了相同的內容( ”hello” )的對象,實際上我們不需要這么三個獨立的對象 ——? 因為要運行它們的話既浪費時間又浪費內存。
    ?
      那么怎樣才能確保 String 對象不會重復呢?下一個話題會涵蓋對于內建 String 機制的興趣。
    ?
    滯留字符串的優化作用
      同一個字符串對象被重復地創建是不必要的, String.intern?() 方法可以避免這種情況。下圖說明了 String.intern() 方法是如何工作的, String.intern() 方法檢查字符串對象的存在性,如果需要的字符串對象已經存在,那么它會將引用指向已經存在的字符串對象而不是重新創建一個。下圖描繪了使用了 intern() 方法的字符串字面量和字符串對象的創建情況。
    ?
    string_creating_with_intern()?method
    下面的例程幫助大家了解 String.intern() 方法的重要性。
    StringTest2.java
    ?
    package?com.performance.string;
    //?This?class?shows?the?use?of?intern()?method?to?improve?performance
    public?class?StringTest2?{
    public?static?void?main(String[]?args){
    ????//?create?String?references?like?s1,s2,s3...so?on..
    ????String?variables[]?=?new?String[50000];
    ????for(?int?i=0;i<variables.length;i++){
    ????????variables[i]?=?"s"+i;
    ????}
    ????//?create?String?literals
    ????long?startTime0?=?System.currentTimeMillis();
    ????for(int?i=0;i<variables.length;i++){
    ????????variables[i]?=?"hello";
    ????}
    ????long?endTime0?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?creation?of?String?literals?:?"
    ?????????????????????????+?(endTime0?-?startTime0)?+?"?milli?seconds"?);
    ????//?create?String?objects?using?'new'?keyword???????
    ????long?startTime1?=?System.currentTimeMillis();
    ????for(int?i=0;i<variables.length;i++){
    ????????variables[i]?=?new?String("hello");
    ????}
    ????long?endTime1?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?creation?of?String?objects?with?'new'?key?word?:?"
    ????????????????????????+?(endTime1?-?startTime1)+"?milli?seconds");
    ????//?intern?String?objects?with?intern()?method???
    ????long?startTime2?=?System.currentTimeMillis();
    ????for(int?i=0;i<variables.length;i++){
    ????????variables[i]?=?new?String("hello");
    ????????variables[i]?=?variables[i].intern();
    ????}
    ????long?endTime2?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?creation?of?String?objects?with?intern():?"
    ????????????????????????+?(endTime2?-?startTime2)+"?milli?seconds");
    ????}
    }
    這是上面那段代碼的輸出結果:
    Time?taken?for?creation?of?String?literals?:?0?milli?seconds
    Time?taken?for?creation?of?String?objects?with?'new'?key?word?:?160?milli?seconds
    Time?taken?for?creation?of?String?objects?with?intern():?60?milli?seconds
    ?
    連接字符串時候的優化技巧
      你可以使用 + 操作符或者 String.concat() 或者 StringBuffer.append() 等辦法來連接多個字符串,那一種辦法具有最佳的性能呢?
      如何作出選擇取決于兩種情景,第一種情景是需要連接的字符串是在編譯期決定的還是在運行期決定的,第二種情景是你使用的是 ?StringBuffer 還是 String 。通常程序員會認為 StringBuffer.append() 方法會優于 + 操作符或 ?String.concat() 方法,但是在一些特定的情況下這個假想是不成立的。
    ?
    1)?
    第一種情景:編譯期決定相對于運行期決定
    請看下面的 StringTest3.java 代碼和輸出結果。

    package?com.performance.string;
    /**?This?class?shows?the?time?taken?by?string?concatenation?at?compile?time?and?run?time.*/
    public?class?StringTest3?{
    ??public?static?void?main(String[]?args){
    ????//Test?the?String?Concatination
    ????long?startTime?=?System.currentTimeMillis();
    ????for(int?i=0;i<5000;i++){
    ????String?result?=?"This?is"+?"testing?the"+?"difference"+?"between"+
    ????????????"String"+?"and"+?"StringBuffer";
    ????}
    ????long?endTime?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?string?concatenation?using?+?operator?:?"
    ?????????+?(endTime?-?startTime)+?"?milli?seconds");
    ????//Test?the?StringBuffer?Concatination
    ????long?startTime1?=?System.currentTimeMillis();
    ????for(int?i=0;i<5000;i++){
    ????StringBuffer?result?=?new?StringBuffer();
    ?????????result.append("This?is");
    ????????result.append("testing?the");
    ????????result.append("difference");
    ????????result.append("between");
    ???????result.append("String");
    ???????result.append("and");
    ???????result.append("StringBuffer");
    ?????}
    ????long?endTime1?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?String?concatenation?using?StringBuffer?:?"
    ???????????+?(endTime1?-?startTime1)+?"?milli?seconds");
    ??}
    }
    這是上面的代碼的輸出結果:
    Time?taken?for?String?concatenation?using?+?operator?:?0?milli?seconds
    Time?taken?for?String?concatenation?using?StringBuffer?:?50?milli?seconds
    很有趣地, + 操作符居然比 StringBuffer.append() 方法要快,為什么呢?
    ?
      這里編譯器的優化起了關鍵作用,編譯器像下面舉例的那樣簡單地在編譯期連接多個字符串。它使用編譯期決定取代運行期決定,在你使用 new 關鍵字來創建 String 對象的時候也是如此。
    ?
    編譯前:
    String?result?=?"This?is"+"testing?the"+"difference"+"between"+"String"+"and"+"StringBuffer";
    編譯后:
    String?result?=?"This?is?testing?the?difference?between?String?and?StringBuffer";

    這里 String 對象在編譯期就決定了而 StringBuffer 對象是在運行期決定的。運行期決定需要額外的開銷當字符串的值無法預先知道的時候,編譯期決定作用于字符串的值可以預先知道的時候,下面是一個例子。
    ?
    編譯前:
    public?String?getString(String?str1,String?str2)?{
    ????return?str1+str2;
    }
    編譯后:
    return?new?StringBuffer().append(str1).append(str2).toString();
    運行期決定需要更多的時間來運行。
    ?
    2)?
    第二種情景:使用 StringBuffer 取代 String
    看看下面的代碼你會發現與情景一相反的結果 —— 連接多個字符串的時候 StringBuffer 要比 String 快。
    StringTest4.java
    ?
    package?com.performance.string;
    /**?This?class?shows?the?time?taken?by?string?concatenation
    using?+?operator?and?StringBuffer??*/
    public?class?StringTest4?{
    ?public?static?void?main(String[]?args){
    ????//Test?the?String?Concatenation?using?+?operator
    ????long?startTime?=?System.currentTimeMillis();
    ????String?result?=?"hello";
    ????for(int?i=0;i<1500;i++){
    ????????result?+=?"hello";
    ????}
    ????long?endTime?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?string?concatenation?using?+?operator?:?"
    ??????????????????+?(endTime?-?startTime)+?"?milli?seconds");
    ????//Test?the?String?Concatenation?using?StringBuffer
    ????long?startTime1?=?System.currentTimeMillis();
    ????StringBuffer?result1?=?new?StringBuffer("hello");
    ????for(int?i=0;i<1500;i++){
    ????????result1.append("hello");
    ????}
    ????long?endTime1?=?System.currentTimeMillis();
    ????System.out.println("Time?taken?for?string?concatenation?using?StringBuffer?:??"
    ??????????????????+?(endTime1?-?startTime1)+?"?milli?seconds");
    ????}
    }
    這是上面的代碼的輸出結果:
    Time?taken?for?string?concatenation?using?+?operator?:?280?milli?seconds
    Time?taken?for?String?concatenation?using?StringBuffer?:?0?milli?seconds
    看得出 StringBuffer.append() 方法要比 + 操作符要快得多,為什么呢?

      原因是兩者都是在運行期決定字符串對象,但是 + 操作符使用不同于 StringBuffer.append() 的規則通過 String StringBuffer 來完成字符串連接操作。(譯注:什么樣的規則呢?)
    ?
    借助 StringBuffer 的初始化過程的優化技巧
      你可以通過 StringBuffer 的構造函數來設定它的初始化容量,這樣可以明顯地提升性能。這里提到的構造函數是 StringBuffer(int?length) length 參數表示當前的 StringBuffer 能保持的字符數量。你也可以使用 ensureCapacity(int?minimumcapacity) 方法在 StringBuffer 對象創建之后設置它的容量。首先我們看看 StringBuffer 的缺省行為,然后再找出一條更好的提升性能的途徑。
    ?
    StringBuffer
    的缺省行為:
       StringBuffer 在內部維護一個字符數組,當你使用缺省的構造函數來創建 StringBuffer 對象的時候,因為沒有設置初始化字符長度, StringBuffer 的容量被初始化為 16 個字符,也就是說缺省容量就是 16 個字符。當 StringBuffer 達到最大容量的時候,它會將自身容量增加到當前的 2 倍再加 2 ,也就是( 2* 舊值 +2 )。
      如果你使用缺省值,初始化之后接著往里面追加字符,在你追加到第 16 個字符的時候它會將容量增加到 34 2*16+2 ),當追加到 34 個字符的時候就會將容量增加到 70 2*34+2 )。無論何事只要 StringBuffer 到達它的最大容量它就不得不創建一個新的字符數組然后重新將舊字符和新字符都拷貝一遍 —— 這也太昂貴了點。所以總是給 StringBuffer 設置一個合理的初始化容量值是錯不了的,這樣會帶來立竿見影的性能增益。
      我利用兩個 StringBuffer 重新測試了上面的 StringTest4.java 代碼,一個未使用初始化容量值而另一個使用了。這次我追加了 50000 ’hello’ 對象沒有使用 + 操作符。區別是我使用 StringBuffer(250000) 的構造函數來初始化第二個 ?StringBuffer 了。
    ?
    輸出結果如下:
    Time?taken?for?String?concatenation?using?StringBuffer?with?out?setting?size:?280?milli?seconds
    Time?taken?for?String?concatenation?using?StringBuffer?with?setting?size:?0?milli?seconds
    StringBuffer
    初始化過程的調整的作用由此可見一斑。所以,使用一個合適的容量值來初始化 StringBuffer 永遠都是一個最佳的建議。
    ?
    關鍵點
    1.?
    無論何時只要可能的話使用字符串字面量來常見字符串而不是使用 new 關鍵字來創建字符串。
    2.?
    無論何時當你要使用 new 關鍵字來創建很多內容重復的字符串的話,請使用 String.intern() 方法。
    3.?+
    操作符會為字符串連接提供最佳的性能 —— 當字符串是在編譯期決定的時候。
    4.?
    如果字符串在運行期決定,使用一個合適的初期容量值初始化的 StringBuffer 會為字符串連接提供最佳的性能。

    ?

    posted on 2006-11-10 10:44 honzeland 閱讀(213) 評論(0)  編輯  收藏 所屬分類: JAVA

    主站蜘蛛池模板: 国产成人免费高清激情明星| 国产久爱免费精品视频| 99re6在线视频精品免费下载 | 免费人成网站在线高清| 亚洲老熟女五十路老熟女bbw| 人禽杂交18禁网站免费| 亚洲精品无码专区久久| 精品少妇人妻AV免费久久洗澡| 亚洲欧美日本韩国| 四虎影永久在线高清免费| 特级aaaaaaaaa毛片免费视频| 亚洲成人一区二区| 十八禁视频在线观看免费无码无遮挡骂过 | 国产人成免费视频| 美女黄频a美女大全免费皮| 激情综合色五月丁香六月亚洲| 中文字幕无码免费久久9一区9| 亚洲成AV人片在线播放无码| 亚洲精品免费在线视频| 亚洲爆乳精品无码一区二区| 免费一看一级毛片人| 成人av片无码免费天天看| 亚洲综合自拍成人| 大地资源二在线观看免费高清 | 亚洲综合成人婷婷五月网址| 国产嫩草影院精品免费网址| 黄视频在线观看免费| 亚洲国产成人久久精品动漫| 久久久久国色AV免费看图片| 看成年女人免费午夜视频| 国产啪亚洲国产精品无码| 59pao成国产成视频永久免费| 亚洲乱色伦图片区小说| 在线亚洲精品自拍| 久久精品国产免费观看| 美女免费精品高清毛片在线视| 国产av天堂亚洲国产av天堂 | 国产免费高清69式视频在线观看| 亚洲成亚洲乱码一二三四区软件| 黄页免费的网站勿入免费直接进入| 亚洲欧美成人综合久久久|