String StringBuffer StringBuilder 區別
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
.線程安全的可變字元序列。一個類似 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池用來存放運作時產生的各種字串,
且池中的字串的內容不重複。而一般物件不存在這個緩衝池,並且所建立的物件僅僅存在於方法的堆疊區。
其一,使用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; .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.print b = "a" + bb; false
分析:JVM對於字串引用,由於在字串的"+"連接中,有字串引用存在,而引用的值在程式編譯期是無法確定的,即"a" + bb無法被編譯器最佳化,只有在程式運行期來動態分配並將連接後的新位址賦給b。所以上面程式的結果也就為false。
[3]
String a = "ab";
final String bb = "b";
String b = "a" + bb;
System.out.println((a ult)); = true
分析:和[3]中唯一不同的是bb字串加了final修飾,對於final修飾的變量,它在編譯時被解析為常數值的一個本地拷貝存儲到自己的常數池中或嵌入到它的字節碼流中。
所以此時的"a" + bb和"a" + "b"效果是一樣的。故上面程式的結果為true。
[4]
String a = "ab";
final String bb = getBB();
String b = "a" + bb;
System
String b = "a" + bb;
System。 = false
private static String getBB() { return "b"; }
分析:JVM對於字串引用bb,它的值在編譯期間無法確定,只有在程式執行期呼叫方法後,將方法的傳回值與字串和"a"來動態連線並指派位址為b,故上面程式的結果為false。
透過上面4個例子可以得知:
String s = "a" + "b" + "c"; 就等價於String s = "abc"
String
String b = "b";
String c = "c";
String s = a uffer 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 }
}
每做一次+ 就產生個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 = "; 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的值相等。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

該專案為了方便開發者更快監控多個遠端主機jvm,如果你的專案是Spring boot那麼很方便集成,jar包引入即可,不是Spring boot也不用氣餒,你可以快速自行初始化一個Spirng boot程式引入jar包即可

透過JVM命令列參數,您可以細微地調整JVM行為。其中通用參數包括:設定Java堆大小(-Xms、-Xmx)設定新生代大小(-Xmn)啟用平行垃圾收集器(-XX:+UseParallelGC)減少Survivor區記憶體佔用(-XX:-ReduceSurvivorSetInMemory)消除冗餘餘垃圾回收(-XX:-EliminateRedundantGCs)列印垃圾回收資訊(-XX:+PrintGC)使用G1垃圾收集器(-XX:-UseG1GC)設定最大垃圾回收暫停時間(-XX:MaxGCPau

掌握JVM記憶體使用量的重點與注意事項JVM(JavaVirtualMachine)是Java應用程式運作的環境,其中最為重要的就是JVM的記憶體管理。合理地管理JVM記憶體不僅可以提高應用程式的效能,還可以避免記憶體洩漏和記憶體溢位等問題。本文將介紹JVM記憶體使用的要點和注意事項,並提供一些具體的程式碼範例。 JVM記憶體分區JVM記憶體主要分為以下區域:堆(He

JVM虛擬機的作用及原理解析簡介:JVM(JavaVirtualMachine)虛擬機是Java程式語言的核心組成部分之一,它是Java的最大賣點之一。 JVM的作用是將Java原始碼編譯成字節碼,並負責執行這些字節碼。本文將介紹JVM的作用及其運作原理,並提供一些程式碼範例以幫助讀者更好地理解。作用:JVM的主要作用是解決了不同平台上Java程式的可移

Java是一種流行的程式語言,在開發Java應用程式的過程中,可能會遇到JVM記憶體溢位錯誤。這種錯誤通常會導致應用程式崩潰,影響用戶體驗。本文將探討JVM記憶體溢位錯誤的原因和如何處理和避免這種錯誤。 JVM記憶體溢位錯誤是什麼? Java虛擬機器(JVM)是Java應用程式的運作環境。在JVM中,記憶體被分為多個區域,其中包括堆疊、方法區、堆疊等。堆是用於存儲創建的對象的

在寫java程式來檢查JVM是32位元還是64位元之前,我們先討論一下JVM。 JVM是java虛擬機,負責執行字節碼。它是Java執行時間環境(JRE)的一部分。我們都知道java是平台無關的,但是JVM是平台相關的。我們需要為每個作業系統提供單獨的JVM。如果我們有任何java原始碼的字節碼,由於JVM,我們可以輕鬆地在任何平台上運行它。 java檔案執行的整個過程如下-首先,我們保存擴展名為.java的java原始碼,編譯器將其轉換為擴展名為.class的字節碼。這發生在編譯時。現在,在運行時,J

JVM記憶體參數設定:如何合理調整堆記憶體大小?在Java應用程式中,JVM是負責管理記憶體的關鍵元件。其中,堆記憶體是用來儲存物件實例的地方,堆記憶體的大小設定對應用程式的效能和穩定性有著重要影響。本文將介紹如何合理調整堆記憶體大小的方法,並附帶具體程式碼範例。首先,我們需要了解一些關於JVM記憶體的基礎知識。 JVM的記憶體分成了幾個區域,包括堆疊記憶體、堆疊記憶體、方法區等。其中

JVM原理詳解:深入探究Java虛擬機的工作原理,需要具體程式碼範例一、引言隨著Java程式語言的快速發展和廣泛應用,Java虛擬機(JavaVirtualMachine,簡稱JVM)也成為了軟體開發中不可或缺的一部分。 JVM作為Java程式的運作環境,能夠提供跨平台的特性,使得Java程式能夠在不同的作業系統上運作。在本文中,我們將深入探討JVM的工作原
