我也可以證明,要想學好Java程式設計,必須得把String的馬步給紮得穩穩的。之前,我自以為有了幾年程式設計經驗,覺得String這些老生常談的話題(比如equals與==)可真是無聊!但事實并非如此,這些基礎知識需要反複的傳播和推廣!
請允許我先舉一個例子(請勿對号入座):
有小夥伴在沉默王二技術交流群裡發了下面這樣一幅圖檔,問:“我這樣判斷字元串為空 正确嗎?”
我沒敢輕易下結論,仔仔細細的看了好一遍;先判null,之後把entName放在equals的參數位置判空,我覺得這位小夥的代碼寫得很完美啊。
但意想不到的是,小夥伴緊接着說:“但是我調試,是null的時候還是進入if ”。
我當時回答說:“那你的調試肯定是瞎調,或者見鬼了。嘿嘿”
我當時詫異極了。幸好之後小夥伴發來debug的截圖!
你說呢,這樣寫不報錯才怪!
之後我稍解釋了一番,并回複說:“建議啊,不是我打擊啊,還是多紮紮馬步比較好”。
下面我們就細緻來說一下String不得不明白的3個點。
1、檢查String是否相等
如上文提到的,檢查String是否相等最好要使用equals方法,盡量少使用==操作符。
String cmower ="cmower";
System.out.println("cmower" == cmower);//true
System.out.println("cmower".equals(cmower));//true
System.out.println("cmower".substring(0, 3) == "cmo");//false
System.out.println("cmower".substring(0, 3).equals("cmo"));//true
==操作符确定的是兩個String是否放在同一個位置上。
“cmower”字元串和cmower變量指向的引用就是在同一個位置上,是以==比較結果為true。
在Java虛拟機上,隻有字元串常量是共享的(”cmower”字元串和cmower變量共享了同一個位址)。但是對于substring産生的結果就不共享了。
對于equals,比較的則是兩個對象是否具有相同的字元集。
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
2、String不可變
public static void main(String[] args) {
String s = "s";
String ss = toUpper(s);
System.out.println(s);//s
System.out.println(ss);//S
}
private static String toUpper(String b) {
String bb = b.toUpperCase();
System.out.println(b);//s
return bb;
“s”是一個字元串對象,你怎麼也不能把這個對象變成“S”。也就是說小s和大S盡管是雙胞胎,但她們倆注定都不能成為對方。
3、+與StringBuilder
首先,我們先來看對于+操作符,在Java虛拟機下是如何工作的。
public static String add1() {
String b = "b";
String s = "a" + b + "c" + "d" + 100;
return s;
public static String add2() {
String s = "a" + "b" + "c" + "d" + 100;
對于add1和add2方法,你認為Java虛拟機的工作方式一樣嗎?
閉上眼睛10秒鐘,先想一會。
我們來揭曉答案:
差别是不是很大?
這說明,+操作符在拼接String時,會根據情況做一定的選擇。比如add1方法,Java會new 一個StringBuilder對象,來對abcd100進行append操作,之後再toString出來。
那麼也就說,Java會自動會為我們優化代碼,以後我們盡管使用+操作符就行了。但事實并非如此,再來看一串代碼。
public static String plus() {
String result = "";
for (int i = 0; i < 10; i++) {
result += "a";
}
return result;
public static String sb() {
StringBuilder sb = new StringBuilder();
sb.append("a");
return sb.toString();
這個時候,你選擇用sb方法還是plus方法?
再閉上眼睛10秒鐘,想一下你的答案。
javap執行結果如下:
看得出plus方法的8-34行是一個循環,11行時建立了StringBuilder對象,也就是在循環内。這個方法執行了10次,那麼也就建立了10個StringBuilder對象。
再來看sb方法的結果:
顯而易見,StringBuilder對象隻有一個。
在使用StringBuilder時,盡量少“在append方法的參數中使用+操作符”:
public static String sb1() {
sb.append("a" + b);
這樣做糟糕至極:
“a” + b時又重新建立了StringBuilder對象。
總結如下,
1. 在進行循環多次拼接String時,用StringBuilder而不用+操作符!
2. +操作符隻用于少量字元串變量拼接,在記憶體中操作,性能更高!
3. append方法的參數少用+操作符!
最後,留一個話題讨論一下。
對于substring(int beginIndex, int endIndex)方法,在《Java核心技術卷1》上說,endIndex指的是不想複制的第一個位置。但這句話很拗口。我自己也經常搞不清楚到底endIndex該為多少,總是怕搞錯,最後非要輸出結果确認一下!
問:“如何更好的确定endIndex?”
"cmower".substring(0, 3);