2025-02-10

1. String對象內容是不可改變的,StringBuffer是可以改變的,並且高效;


2. String
String a = “123”;
a = a + “456”;
上面兩句,雖然a的值最終改變瞭,但是實際上在編譯的時候,第一句a是一個對象,被分配瞭一個地址,第二句執行時,原來的a被釋放,然後重新分配。
a 原本指向一 String object instance (“123”), a + “456” 會造出另一新的 String object instance (“123456”), 然後 a 再指向這新的 String instance.


3. StringBuffer
StringBuffer b = new StringBuffer(“asd”);
b.append(“fgh”);
在這個過程中,隻存在b這麼一個對象,b 一直都指向一個 StringBuffer instance. append 也隻是改變此 instance 的內容而已.



看看以下代碼:
將26個英文字母重復加瞭5000次,
String tempstr = “abcdefghijklmnopqrstuvwxyz”;
int times = 5000;
long lstart1=System.currentTimeMillis();
String str =””;
for(int i=0;i<times;i++)
{
   str+=tempstr;
}


long lend1=System.currentTimeMillis();
long time = (lend1-lstart1);
System.out.println(time);
可惜我的計算機不是超級計算機,得到的結果每次不一定一樣一般為 154735 左右。
也就是154秒。
我們再看看以下代碼
String tempstr = “abcdefghijklmnopqrstuvwxyz”;


int times = 5000;
long lstart2=System.currentTimeMillis();
StringBuffer sb =new StringBuffer();
for(int i=0;i<times;i++)
{
   sb.append(tempstr);
  
}
long lend2=System.currentTimeMillis();
long time2 = (lend2-lstart2);
System.out.println(time2);
得到的結果為 16 有時還是 0
所以結論很明顯,StringBuffer 的速度幾乎是String 上萬倍。當然這個數據不是很準確。因為循環的次數在100000次的時候,差異更大。不信你試試。
下一次我將解釋為什麼StringBuffer 的效率比String 高這麼多。
String與StringBuffer的區別?


如果你在網上一搜,會有非常多的答案,其中最多的就是String是不可變而StringBuffer是可變的,但是這可變與不可變究竟是什麼意思呢?如果你能用IDE進行debug的話,你就會發現,String實例化以後所有的屬性都是final的,而StringBuffer確不是,這就是可變與不可變。下面引用SCJP的試題來解釋一下這個例子:


java 代碼
public class Test {   
   public static void stringReplace (String text) {   
    text = text.replace(j , i);   
    }   
      
   public static void bufferReplace (StringBuffer text) {   
    text = text.append(“C”);   
    }   
      
    public static void main (String args[]) {   
    String textString = new String (“java”);   
    StringBuffer textBuffer = new StringBuffer (“java”);   
       
    stringReplace (textString);   
     bufferReplace (textBuffer);   
       
     System.out.println (textString + textBuffer);   
     }   
     }   
答案是 javajavaC


這是因為第七行text = text.append (“C”),append方法會改變text中的值,而text與textBuffer指向的地址是相同的。因此會打印javaC


再舉個例子:


String a = “a”; //假設a指向地址0x0001


a = “b”;//重新賦值後a指向地址0x0002,但0x0001地址中保存的”a”依舊存在,但已經不再是a所指向的。


因此String的操作都是改變賦值地址而不是改變值操作


一個String對象的長度是固定的,不能改變它的內容,或者是附加新的字符至String對象中。您也許會使用+來串聯字符串以達到附加新字符或字符串的目的,但+會產生一個新的String實例。如果程序對這種附加字符串的需求很頻繁,並不建議使用+來進行字符串的串聯。在面向對象程序設計中,最好是能重復運用已生成的對象,對象的生成需要內存空間與時間,不斷地產生String實例是一個沒有效率的行為。
J2SE 5.0提供java.lang.StringBuilder類,使用這個類所產生的對象默認會有16個字符的長度,您也可以自行指定初始長度。如果附加的字符超出可容納的長度,則StringBuilder對象會自動增加長度以容納被附加的字符。如果有頻繁作字符串附加的需求,使用StringBuilder會讓程序的效率大大提高。通過下面的簡單測試程序就可以知道效能差距有多大。
ü 范例6.5 AppendStringTest.java
public class AppendStringTest {
public static void main(String[] args) {
String text = ” “;


long beginTime = System.currentTimeMillis();
for(int i = 0; i < 10000; i++)
text = text + i;
long endTime = System.currentTimeMillis();
System.out.println( “執行時間: ” + (endTime – beginTime));


StringBuilder builder = new StringBuilder( ” “);
beginTime = System.currentTimeMillis();
for(int i = 0; i < 10000; i++)
builder.append(String.valueOf(i));
endTime = System.currentTimeMillis();
System.out.println( “執行時間: ” + (endTime – beginTime));
}
}


在范例6.5中首先使用+來串聯字符串,使用System.currentTimeMillis()取得for循環執行前、後的系統時間,這樣就可以得知for循環執行瞭多久。以下是我的計算機上的測試數據:


執行時間:4641
執行時間:16
可以看到執行的時間差距很大,這說明瞭使用+串聯字符串所帶來的負擔。如果有經常作附加字符串的需求,建議使用StringBuilder。事實上就范例6.5來說,第二個for循環執行時間還可以更短,因為append()也可以接受基本數據類型,所以不必特地使用String.valueOf()方法從int取得String。改為以下的方式,執行時間可以大幅縮短:
for(int i = 0; i < 10000; i++)
builder.append(i);
使用StringBuilder最後若要輸出字符串結果,可以用toString()方法。可以使用length()方法得知目前對象中的字符長度,而capacity()可返回該對象目前可容納的字符容量。另外,StringBuilder還有像insert()方法可以將字符插入指定的位置,如果該位置以後有字符,則將所有的字符往後移;deleteChar()方法可以刪除指定位置的字符,而reserve()方法可以反轉字符串。詳細的使用可以查詢java.lang.StringBuilder的API文件說明。
StringBuilder是J2SE 5.0才新增的類,在J2SE 5.0之前的版本若有相同的需求,則使用java.lang.StringBuffer。事實上,StringBuilder被設計為與StringBuffer具有相同的操作接口。在單機非多線程(Multithread)的情況下使用StringBuilder會有較好的效率,因為StringBuilder沒有處理同步(Synchronized)問題。StringBuffer則會處理同步問題,如果StringBuilder會在多線程下被操作,則要改用StringBuffer,讓對象自行管理同步問題。


 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *