1、String中的每個字元都是一個16位的Unicode字元,用Unicode很容易表達豐富的國際化字元集,比如很好的中文支援。甚至Java的標識符都可以用漢字,但是沒人會用吧(只在一本清華的《Java2實用教程》看過)。
2、判斷Null 字元串。根據需要自己選擇某個或者它們的組合
if ( s == null ) //從引用的角度
if ( s.length() == 0 ) //從長度判別
if ( s.trim().length () == 0 ) //是否有多個空白字元
trim()方法的作用是是移除前置和尾部的Unicode值小於'"u0020'的字元,並返回“修剪”好的字串。這種方法很常用,比如需要使用者輸入使用者名稱,使用者不小心加了前置或者尾部空格,一個好的程式應該知道使用者不是故意的,即使是故意的也應該智能點地處理。
判斷空串是很常用的操作,但是Java類庫直到1.6才提供了isEmpty()方法。若且唯若 length() 為 0 時返回 true。
3、未初始化、空串""與null。它們是不同的概念。對未初始化的對象操作會被編譯器擋在門外;null是一個特殊的初始化值,是一個不指向任何對象的引用,對引用為null的對象操作會在運行時拋出異常NullPointerException;而空串是長度為0的字串,和別的字串的唯一區別就是長度為0。
例子:
public class StringTest{
static String s1;
public static void main(String[] args) {
String s2;
String s3 = "";
System.out.print(s1.isEmpty()); //運行時異常
System.out.print(s2.isEmpty()); //編譯出錯
System.out.print(s3.isEmpty()); //ok!輸出true
}
}
4、String類的方法很多,在編寫相關代碼的時候看看JDK文檔時有好處的,要不然花了大量時間實現一個已經存在的方法是很不值得的,因為編寫、測試、維護自己的代碼使項目的成本增加,利潤減少,嚴重的話會導致開不出工資……
5、字串的比較。
Java不允許自訂動作符重載,因此字串的比較要用compareTo() 或者 compareToIgnoreCase()。s1.compareTo(s2),傳回值大於0則,則前者大;等於0,一般大;小於0,後者大。比較的依據是字串中各個字元的Unicode值。
6、toString()方法。
Java的任何對象都有toString()方法,是從Object對象繼承而來的。它的作用就是讓對象在輸出時看起來更有意義,而不是奇怪的對象的記憶體位址。對測試也是很有協助的。
7、String對象是不變的!可以變化的是String對象的引用。
String name = "ray";
name.concat("long"); //字串串連
System.out.println(name); //輸出name,ok,還是"ray"
name = name.concat("long"); //把字串對象串連的結果賦給了name引用
System.out.println(name); //輸出name,oh!,變成了"raylong"
上述三條語句其實產生了3個String對象,"ray","long","raylong"。第2條語句確實產生了"raylong"字串,但是沒有指定把該字串的引用賦給誰,因此沒有改變name引用。第3條語句根據不變性,並沒有改變"ray",JVM建立了一個新的對象,把"ray","long"的串連賦給了name引用,因此引用變了,但是原對象沒變。
8、String的不變性的機制顯然會在String常量內有大量的冗餘。如:"1" + "2" + "3" +......+ "n" 產生了n+(n+1)個String對象!因此Java為了更有效地使用記憶體,JVM留出一塊特殊的記憶體地區,被稱為“String常量池”。對String多麼照顧啊!當編譯器遇見String常量的時候,它檢查該池內是否已經存在相同的String常量。如果找到,就把新常量的引用指向現有的String,不建立任何新的String常量對象。
那麼就可能出現多個引用指向同一個String常量,會不會有別名的危險呢?No problem!String對象的不變性可以保證不會出現別名問題!這是String對象與普通對象的一點區別。
乍看起來這是底層的機制,對我們編程沒什麼影響。而且這種機制會大幅度提高String的效率,實際上卻不是這樣。為串連n個字串使用字串串連操作時,要消耗的時間是n的平方級!因為每兩個字串串連,它們的內容都要被複製。因此在處理大量的字串串連時,而且要求效能時,我們不要用String,StringBuffer是更好的選擇。
8、StringBuffer類。StringBuffer類是可變的,不會在字串常量池中,而是在堆中,不會留下一大堆無用的對象。而且它可將字串緩衝區安全地用於多個線程。每個StringBuffer對象都有一定的容量。只要StringBuffer對象所包含的字元序列的長度沒有超出此容量,就無需分配新的內部緩衝區數組。如果內部緩衝區溢位,則此容量自動增大。這個固定的容量是16個字元。我給這種演算法起個名字叫“添飯演算法”。先給你一滿碗飯,不夠了再給你一滿碗飯。
例子:
StringBuffer sb = new StringBuffer(); //初始容量為 16 個字元
sb.append("1234"); //這是4個字元,那麼16個字元的容量就足夠了,沒有溢出
System.out.println(sb.length()); //輸出字串長度是4
System.out.println(sb.capacity()); //輸出該字串緩衝區的容量是16
sb.append("12345678901234567"); //這是17個字元,16個字元的容量不夠了,擴容為17+16個字元的容量
System.out.println(sb.length()); //輸出字串長度是17
System.out.println(sb.capacity()); //輸出該字串緩衝區的容量是34
sb.append("890").reverse().insert(10,"-");
System.out.println(sb); //輸出0987654321-09876543214321
字串的長度和字元緩衝區的容量是兩個概念,注意區別。
還有串聯的方式看起來是不是很酷!用傳回值串連起來可以實現這種簡潔和優雅。
10、StringBuilder類。 從J2SE 5.0 提供了StringBuilder類,它和StringBuffer類是孿生兄弟,很像。它存在的價值在於:對字串操作的效率更高。不足的是安全執行緒無法保證,不保證同步。那麼兩者效能到底差多少呢?很多!
請參閱:http://book.csdn.net/bookfiles/135/1001354628.shtml
實踐:
單個線程的時候使用StringBuilder類,以提高效率,而且它的API和StringBuffer相容,不需要額外的學習成本,物美價廉。多線程時使用StringBuffer,以保證安全。
11、字串的比較。
下面這條可能會讓你暈,所以你可以選擇看或者不看。它不會對你的職業生涯造成任何影響。而且謹記一條,比較字串要用equals()就ok了!一旦用了“==”就會出現很怪異的現象。之所以把這部分放在最後,是想節省大家的時間,因為這條又臭又長。推薦三種人:一、沒事閑著型。二、想深入地理解Java的字串,即使明明知道學了也沒用。三、和我一樣愛好研究“茴”字有幾種寫法。
還是那句老話,String太特殊了,以至於某些規則對String不起作用。個人感覺這種特殊性並不好。看例子:
例子A:
String str1 = "java";
String str2 = "java";
System.out.print(str1==str2);
地球上有點Java基礎的人都知道會輸出false,因為==比較的是引用,equals比較的是內容。不是我忽悠大家,你們可以在自己的機子上運行一下,結果是true!原因很簡單,String對象被放進常量池裡了,再次出現“java”字串的時候,JVM很興奮地把str2的引用也指向了“java”對象,它認為自己節省了記憶體開銷。不難理解吧 呵呵
例子B:
String str1 = new String("java");
String str2 = new String("java");
System.out.print(str1==str2);
看過上例的都學聰明了,這次肯定會輸出true!很不幸,JVM並沒有這麼做,結果是false。原因很簡單,例子A中那種聲明的方式確實是在String常量池建立“java”對象,但是一旦看到new關鍵字,JVM會在堆中為String分配空間。兩者聲明方式貌合神離,這也是我把“如何建立字串對象”放到後面來講的原因。大家要沉住氣,還有一個例子。
例子C:
String str1 = "java";
String str2 = "blog";
String s = str1+str2;
System.out.print(s=="javablog");
再看這個例子,很多同志不敢妄言是true還是false了吧。愛玩腦筋急轉彎的人會說是false吧……恭喜你,你會搶答了!把那個“吧”字去掉你就完全正確。原因很簡單,JVM確實會對型如String str1 = "java"; 的String對象放在字串常量池裡,但是它是在編譯時間刻那麼做的,而String s = str1+str2; 是在運行時刻才能知道(我們當然一眼就看穿了,可是Java必須在運行時才知道的,人腦和電腦的結構不同),也就是說str1+str2是在堆裡建立的,s引用當然不可能指向字串常量池裡的對象。沒崩潰的人繼續看例子D。
例子D:
String s1 = "java";
String s2 = new String("java");
System.out.print(s1.intern()==s2.intern());
intern()是什麼東東?反正結果是true。如果沒用過這個方法,而且訓練有素的程式員會去看JDK文檔了。簡單點說就是用intern()方法就可以用“==”比較字串的內容了。在我看到intern()方法到底有什麼用之前,我認為它太多餘了。其實我寫的這一條也很多餘,intern()方法還存在諸多的問題,如效率、實現上的不統一……
例子E:
String str1 = "java";
String str2 = new String("java");
System.out.print(str1.equals(str2));
無論在常量池還是堆中的對象,用equals()方法比較的就是內容,就這麼簡單