String StringBuffer StringBuilder區別

來源:互聯網
上載者:User
String 字串常量
StringBuffer 字串變數(安全執行緒)
StringBuilder 字串變數(非安全執行緒)
簡要的說, String 類型和 StringBuffer 類型的主要效能區別其實在於 String 是不可變的對象, 因此在每次對 String 類型進行改變的時候其實都等同於產生了一個新的 String 對象,然後將指標指向新的 String 對象,所以經常改變內容的字串最好不要用 String ,因為每次產生對象都會對系統效能產生影響,特別當記憶體中無引用對象多了以後, JVM 的 GC 就會開始工作,那速度是一定會相當慢的。
而如果是使用 StringBuffer 類則結果就不一樣了,每次結果都會對 StringBuffer 對象本身進行操作,而不是產生新的對象,再改變對象引用。所以在一般情況下我們推薦使用 StringBuffer ,特別是字串對象經常改變的情況下。而在某些特別情況下, String 對象的字串拼接其實是被 JVM 解釋成了 StringBuffer 對象的拼接,所以這些時候 String 對象的速度並不會比 StringBuffer 對象慢,而特別是以下的字串對象產生中, String 效率是遠要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你會很驚訝的發現,產生 String S1 對象的速度簡直太快了,而這個時候 StringBuffer 居然速度上根本一點都不佔優勢。其實這是 JVM 的一個把戲,在 JVM 眼裡,這個
String S1 = “This is only a” + “ simple” + “test”; 其實就是:
String S1 = “This is only a simple test”; 所以當然不需要太多的時間了。但大家這裡要注意的是,如果你的字串是來自另外的 String 對象的話,速度就沒那麼快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
這時候 JVM 會規規矩矩的按照原來的方式去做

在大部分情況下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer安全執行緒的可變字元序列。一個類似於 String 的字串緩衝區,但不能修改。雖然在任意時間點上它都包含某種特定的字元序列,但通過某些方法調用可以改變該序列的長度和內容。
可將字串緩衝區安全地用於多個線程。可以在必要時對這些方法進行同步,因此任意特定執行個體上的所有操作就好像是以串列順序發生的,該順序與所涉及的每個線程進行的方法調用順序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重載這些方法,以接受任意類型的資料。每個方法都能有效地將給定的資料轉換成字串,然後將該字串的字元追加或插入到字串緩衝區中。append 方法始終將這些字元添加到緩衝區的末端;而 insert 方法則在指定的點添加字元。
例如,如果 z 引用一個當前內容是“start”的字串緩衝區對象,則此方法調用 z.append("le") 會使字串緩衝區包含“startle”,而 z.insert(4, "le") 將更改字串緩衝區,使之包含“starlet”。
在大部分情況下 StringBuilder > StringBuffer
java.lang.StringBuilde
java.lang.StringBuilder一個可變的字元序列是5.0新增的。此類提供一個與 StringBuffer 相容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字串緩衝區被單個線程使用的時候(這種情況很普遍)。如果可能,建議優先採用該類,因為在大多數實現中,它比 StringBuffer 要快。兩者的方法基本相同。
=========================================================================
String類詳解
1、String類是final的,不可被繼承。
2、String類是的本質是字元數組char[], 並且其值不可改變。PRivate final char value[];
然後開啟String類的API文檔,可以發現:
3、String類對象有個特殊的建立的方式,就是直接指定比如String x = "abc","abc"就表示一個字串對象。而x是"abc"對象的地址,也叫

做"abc"對象的引用。
4、String對象可以通過“+”串聯。串聯後會產生新的字串。也可以通過concat()來串聯,這個後面會講述。
6、Java運行時會維護一個String Pool(String池),JavaDoc翻譯很模糊“字串緩衝區”。String池用來存放運行時中產生的各種字串,

並且池中的字串的內容不重複。而一般對象不存在這個緩衝池,並且建立的對象僅僅存在於方法的堆棧區。


5、建立字串的方式很多,歸納起來有三類:
其一,使用new關鍵字建立字串,比如String s1 = new String("abc");
其二,直接指定。比如String s2 = "abc";
其三,使用串聯產生新的字串。比如String s3 = "ab" + "c";

二、String對象的建立

String對象的建立也很講究,關鍵是要明白其原理。
原理1:當使用任何方式來建立一個字串對象s時,Java運行時(運行中JVM)會拿著這個X在String池中找是否存在內容相同的字串對象,

如果不存在,則在池中建立一個字串s,否則,不在池中添加。

原理2:Java中,只要使用new關鍵字來建立對象,則一定會(在堆區或棧區)建立一個新的對象。

原理3:使用直接指定或者使用純字串串聯來建立String對象,則僅僅會檢查維護String池中的字串,池中沒有就在池中建立一個,有則罷

了!但絕不會在堆棧區再去建立該String對象。

原理4:使用包含變數的運算式來建立String對象,則不僅會檢查維護String池,而且還會在堆棧區建立一個String對象。

另外,String的intern()方法是一個本地方法,定義為public native String intern(); intern()方法的價值在於讓開發人員能將注意力集中到

String池上。當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字串(該對象由 equals(Object) 方法確定),則返回池

中的字串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。

三、不可變類
不可改變的字串具有一個很大的優點:編譯器可以把字串設定為共用。
不可變類String有一個重要的優點-它們不會被共用引用。

是這樣的,JAVA為了提高效率,所以對於String類型進行了特別的處理---為string類型提供了串池
定義一個string類型的變數有兩種方式:
string name= "tom ";
string name =new string( "tom ")
使用第一種方式的時候,就使用了串池,
使用第二中方式的時候,就是一種普通的聲明對象的方式
如果你使用了第一種方式,那麼當你在聲明一個內容也是 "tom "的string時,它將使用串池裡原來的那個記憶體,而不會重新分配記憶體,也就是說,string saname= "tom ",將會指向同一塊記憶體

另外關於string類型是不可改變的問題:
string類型是不可改變的,也就是說,當你想改變一個string對象的時候,比如name= "madding "
那麼虛擬機器不會改變原來的對象,而是產生一個新的string對象,然後讓name去指向它,如果原來的那個 "tom "沒有任何對象去引用它,虛擬機器的記憶體回收機制將接收它。
據說這樣可以提高效率!!!
=========================================================================final StringBuffer a = new StringBuffer("111");
final StringBuffer b = new StringBuffer("222");
a=b;//此句編譯不通過
final StringBuffer a = new StringBuffer("111");
a.append("222");//編譯通過
可見,final只對引用的"值"(即記憶體位址)有效,它迫使引用只能指向初始指向的那個對象,改變它的指向會導致編譯期錯誤。至於它所指向的對象的變化,final是不負責的。

String常量池問題的四個例子
下面是幾個常見例子的比較分析和理解:

[1]
String a = "a1";
String b = "a" + 1;
System.out.println((a == b)); //result = true
String a = "atrue";
String b = "a" + "true";
System.out.println((a == b)); //result = true
String a = "a3.4";
String b = "a" + 3.4;
System.out.println((a == b)); //result = true
分析:JVM對於字串常量的"+"號串連,將程式編譯期,JVM就將常量字串的"+"串連最佳化為串連後的值,拿"a" + 1來說,經編譯器最佳化後在class中就已經是a1。在編譯期其字串常量的值就確定下來,故上面程式最終的結果都為true。

[2]
String a = "ab";
String bb = "b";
String b = "a" + bb;
System.out.println((a == b)); //result = false
分析:JVM對於字串引用,由於在字串的"+"串連中,有字串引用存在,而引用的值在程式編譯期是無法確定的,即"a" + bb無法被編譯器最佳化,只有在程式運行期來動態分配並將串連後的新地址賦給b。所以上面程式的結果也就為false。

[3]
String a = "ab";
final String bb = "b";
String b = "a" + bb;
System.out.println((a == b)); //result = true
分析:和[3]中唯一不同的是bb字串加了final修飾,對於final修飾的變數,它在編譯時間被解析為常量值的一個本地拷貝儲存到自己的常量池中或嵌入到它的位元組碼流中。
所以此時的"a" + bb和"a" + "b"效果是一樣的。故上面程式的結果為true。

[4]
String a = "ab";
final String bb = getBB();
String b = "a" + bb;
System.out.println((a == b)); //result = false
private static String getBB() { return "b"; }
分析:JVM對於字串引用bb,它的值在編譯期無法確定,只有在程式運行期調用方法後,將方法的傳回值和"a"來動態串連並分配地址為b,故上面程式的結果為false。

通過上面4個例子可以得出得知:

String s = "a" + "b" + "c"; 就等價於String s = "abc";

String a = "a";
String b = "b";
String c = "c";
String s = a + b + c;
這個就不一樣了,最終結果等於:

StringBuffer temp = new StringBuffer();
temp.append(a).append(b).append(c);
String s = temp.toString();
由上面的分析結果,可就不難推斷出String 採用串連運算子(+)效率低下原因分析,形如這樣的代碼:

public class Test {
public static void main(String args[]) {
String s = null;
for(int i = 0; i < 100; i++) { s += "a"; }
}
}
每做一次 + 就產生個StringBuilder對象,然後append後就扔掉。下次迴圈再到達時重新產生個StringBuilder對象,然後 append 字串,如此迴圈直至結束。 如果我們直接採用 StringBuilder 對象進行 append 的話,我們可以節省 N - 1 次建立和銷毀對象的時間。所以對於在迴圈中要進行字串連線應用程式,一般都是用StringBuffer或StringBulider對象來進行append操作。

String對象的intern方法理解和分析
public class Test4 {
private static String a = "ab";
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s = s1 + s2;
System.out.println(s == a);//false
System.out.println(s.intern() == a);//true
}
}
這裡用到Java裡面是一個常量池的問題。對於s1+s2操作,其實是在堆裡面重新建立了一個新的對象,s儲存的是這個新對象在堆空間的的內容,所以s與a的值是不相等的。而當調用s.intern()方法,卻可以返回s在常量池中的地址值,因為a的值儲存在常量池中,故s.intern和a的值相等。
  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.