String與StringBuffer 理解

String的創建

  String s = "hello";
 JVM先根據內容"hello"查找對象,如果沒有找到,則在heap上創建新對象,並將其賦予s1,否則使用已經存在的對象

  String s = newString("hello");
 JVM直接在heap上創建新的對象,所以在heap中會出現內容相同,地址不同的String對象


String的比較

 "=="       比較地址
 "equals"   比較內容

  舉例:
  String s1 = "hello";
  String s2 = "hello";
  String s3 = new String("hello");

  s1 ==s2;              //true       地址相同
  s1 ==s3;              //false      地址不同
 s1.equals(s2);         //true       內容相同
 s1.equals(s3);         //true       內容相同


intern() 方法

  查找內容相同(equals())的字符串

   String s1 ="hello";               // hello不存在,jvm創建新對象 (1)
   String s2 = newString("hello");   // 創舉新對象 (2),這時heap中存在兩個內容爲hello的對象
   s1 ==s2;          //false       // 地址不同
  s1.equals(s2);     //true        // 內容相同
   s2 =s2.intern();   //true        // 找到對象(1) 並賦予s2
   s1 ==s2;          // true!!     // 注意:此時s1,s2同指向(1)


效率:String 與 StringBuffer

   情景1:
    (1) Stringresult = "hello" + " world";
    (2)StringBuffer result = new String().append("hello").append("world");

       (1) 的效率好於 (2),不要奇怪,這是因爲JVM會做如下處理
       編譯前   String result = "hello"+ " world";
       編譯後   String result = "helloworld";


   情景2:
    (1) publicString getString(String s1, String s2) {
           return s1 + s2;
       }
    (2) publicString getString(String s1, String s2) {
           return new StringBuffer().append(s1).append(s2);
       }

       (1) 的效率與 (2) 一樣,這是因爲JVM會做如下處理
       編譯前   return s1 + s2;
       編譯後   return newStringBuffer().append(s1).append(s2);


   情景3:
    (1) String s= "s1";
             s += "s2";
             s += "s3";
    (2)StringBuffer s = newStringBuffer().append("s1").append("s2").append("s3");

       (2)的效率好於(1),因爲String是不可變對象,每次"+="操作都會造成構造新的String對象


   情景4:
    (1)StringBuffer s = new StringBuffer();
       for (int i = 0; i < 50000; i ++) {
           s.append("hello");
       }
    (2)StringBuffer s = new StringBuffer(250000);
       for (int i = 0; i < 50000; i ++) {
           s.append("hello");
       }
      
       (2) 的效率好於(1),因爲StringBuffer內部實現是char數組,默認初始化長度爲16,每當字符串長度大於char
       數組長度的時候,JVM會構造更大的新數組,並將原先的數組內容複製到新數組,(2)避免了複製數組的開銷
        
關鍵點
   1). 簡單的認爲 .append() 效率好於 "+" 是錯誤的!
    2). 不要使用new 創建 String
    3). 注意.intern() 的使用
    4).在編譯期能夠確定字符串值的情況下,使用"+"效率最高
    5). 避免使用"+=" 來構造字符串
    6).在聲明StringBuffer對象的時候,指定合適的capacity,不要使用默認值(18)
    7).注意以下二者的區別不一樣
       - String s = "a" + "b";
       - String s = "a";
         s += "b";

 

String和StringBuffer之概覽
  創建字符串的較佳途徑
  滯留字符串帶來的優化
  連接字符串時的優化技巧
  藉助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 Stringobjects.
 */
public class StringTest1 {
public static void main(String[] args){
    //create String literals
    longstartTime = System.currentTimeMillis();
    for(inti=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       
    longstartTime1 = System.currentTimeMillis();
    for(inti=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 takenfor creation of String literals : 0 milli seconds
Time taken for creation of String objects : 170 milliseconds
 
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.equals()方法來編碼測試上面提到的區別。==操作符會返回true如果一些引用指向一個相同的對象但不會判斷String對象的內容是否相同;String.equals()方法會返回true如果被操作的String對象的內容相同。對於上面的代碼會有s1==s2,因爲s1和s2兩個引用指向同一個對象,對於上面的代碼,s3.equals(s4)會返回true因爲兩個對象的內容都一樣爲”hello”。你可以從上圖看出這種機制。在這裏有三個獨立的包含了相同的內容(”hello”)的對象,實際上我們不需要這麼三個獨立的對象――因爲要運行它們的話既浪費時間又浪費內存。
 

出自:http://ganzhijie163.blog.163.com/blog/static/473597322007710103251155/?fromdm&fromSearch&isFromSearchEngine=yes

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章