String並不是java的基本類型,它是一個對象,但是,建立String是一種“消費行為”(所謂的“消費行為”,就是指該行為是耗時耗記憶體的行為),而且是一種“誤導性的消費行為”,必須防止盲目依賴String,造成不必要的消費。
對於大多數包括我在內的新手而言,使用String似乎是種理所當然的行為,尤其是學過C++的同學,更是慶幸使用String成為內建支援的行為,即使它不是基本類型。但是,使用String並沒有我們表面上那麼好,凡是“消費行為”,多少都會存在副作用,而String的副作用是非常容易被忽視的,因為我們甚至不曾去探究過(這就是我說它是“誤導性”的原因)!String在java中的真正意義是字串常量,是一個不可被修改的對象。第一次看到這個的時候,我很驚訝:不是可以進行String的串連,像是這樣: String str = "hello"; str += "word";怎麼說是不可被修改的呢?仔細研究就會發現一個驚人的事實,str += "word"這個語句已經建立了新的String了!也就是說,之前的str並沒有被修改,因為它的引用的地址和str += "word"建立的字串"hello word"是不同的。在這短短兩行語句中就已經建立了兩個完全不同的對象,更別提我以前常乾的: for(int i = 0; i < 10; i++){ str += ".."; }這簡直就是一種災難!更加可怕的是,我們過去認為應該是同一個String的情況,像是這樣: String str = "hello"; str = "word";或者: changeString(str); public void changeString(String str){ String str = str.replace(...); }它們其實都是在建立新的String對象,只是我們以前不知道而已。 沒有理解事物的本質就任意的使用,這種行為自古以來就會帶來問題。現在,我們已經真正認清楚String的真面目了,是否該開始尋找解決方案呢?就是尋找String的替代品,沒有副作用的替代品,StringBuilder和StringBuffer。 這兩者的使用都需要使用new,因為它們是顯式的真正對象(String其實也是使用new,只是它是隱式的,我們也可以這樣建立String對象:String str = new String("hello"))。它們之間的區別就在於StringBuffer多了一個執行緒安全性(即同步)的附加好處,方便我們在多線程中安全的使用,其餘基本一樣,所以,這裡單純只是討論StringBuffer。 StringBuffer與String之間不能進行強制類型轉化,但是可以互相轉化,像是這樣: String str1 = "hello"; StringBuffer sb = new StringBuffer(str1); String str2 = sb.toString();我們使用String,最常用的就是進行+=這樣的字串拼接。StringBuffer的拼接並不像String那樣,可以直接使用+,+=,它需要調用方法append(),直接將參數加到字串的後面,不會產生新的對象。這裡要注意,如果是這樣: String str = "hello" + "word"; StringBuffer sb = new StringBuffer("hello").append("word");使用StringBuffer可能並不會比String快,那是因為在JVM裡面,它是這樣處理"hello" + "word":一個字串"hello word",並沒有進行+操作,但如果是這樣: String s1 = "hello"; String s2 = "word"; String str = s1 + s2;String就會顯出原形了! StringBuffer更多提供的是對字串內容的操作,像是插入,反轉等等,這些都可以通過文檔查看相關使用方法,這裡就講一個我們平時很少注意到的方法:trimToSize(),它會將StringBuffer對象的中儲存空間縮小到和字串一樣的長度,減少空間的浪費。 必須注意的是,StringBuffer的equals()並沒有被覆蓋,它依然就是Object的equals(),用於比較地址,所以它無法用來進行字串內容的比較(String就可以)。 StringBuilder,StringBuffer和String三者間的速度比較如下: StringBuilder > StringBuffer > String.即使StringBuffer的使用是最安全的,但是大多數情況下是在單線程下使用字串,不過也不需要擔心,因為只有至少百萬層級的數量才會體現StringBuilder的速度優勢,所以平時這兩者愛用誰就用誰。 如果只是少量的資料,使用String是最方便的,但如果是想要編寫一個類的toString()方法,這時就要注意,如果這個方法中對字串的操作是在迴圈中,使用StringBuffer是最佳的選擇。 使用StringBuffer時,如果是處理較大的資料,而且可預見一定會超容,請盡量確定StringBuffer的最大容量,因為StringBuffer的構造器建立的是一個預設大小(通常是16)的字串數組,若超出,就會重新分配記憶體,建立一個更大的數組,並將原先的數組複製過來,再丟棄舊的數組。這種操作在已經擁有一定大小的容量時,是很可怕的,所以,建立時就指定不會被超過的容量,編譯器會非常感激你的。