String作為java最常用的類,被廣大程序員們蹂躏已久,讓我們又愛又恨,應該如何正確的使用它呢,老姜帶你一起來揭開它神秘的面紗。
一、String類定義時被冠上了final的標識符,決定了它終生不可變的特質。
final:修飾類時,類不可被繼承。
設計初衷:類不需要有子類,類的實現細節不允許改變,並且確信這個類不會被擴展;編譯器會對final進行優化,提高執行效率。
二、String類的任何操作都會生成新的字符串對象。
前面我們講過,String是final的,既然不可改變,自然會生成新的對象。我們看下面一段代碼:
String a = "abc123";
a.subString(3);
system.out.println(a);
以上代碼會輸出什麼呢?答案是abc123,因為a從未被改變,a.subString(3)的結果並未重新賦值給變量a。
三、String常量池
相信有過面試經驗的同學們,肯定遇到過類似這樣的問題:String a = new String("a");這段代碼生成了幾個對象?
我的回答是1個或者2個。
1:如果此行代碼之前定義過“a”這個變量,那麼只會生成new String("a")這麼一個對象。
2:相反,之前未定義過,就會存在“a”以及new String("a")這兩個對象。
ps:有些同學要問了,那麼變量a呢?它不是對象嗎?
a只是一個變量,它存放對象new String("a")的引用,它不能稱之為對象,僅僅是一個別名而已。
我們知道,在函數中定義的一些基本類型的變量和對象的引用變量在函數的棧內存中分配,new創建的對象和數組存放在堆內存中。
除此之外還有一個常量池存在,它是在編譯期被確定的,被保存在class文件中,String常量就包含其中。例如,
String s = “abcd”;
String s2 = “abcd”;
此處只會產生一個對象“abcd”,且存放在常量池中,並且s1==s2 為true。
String s3 = "ab" + "cd";
s3 == s?答案是true,因為編譯器會對直接字符串常量的“+”運算優化為s3 =“abcd”且被存放至常量池中。
四、字符串的拼接
1)少量字符串相加,直接用“+”,如:String a = a1+a2+a3;
2)大量字符串拼接,用StringBuilder,如:
StringBuilder sb = new StringBuilder();
for(int i=0;i<100;i++){
sb.append(i);
}
String s = sb.toString();
StringBuilder內部維護了一個初始值為16的char型數組,容積不足時2倍擴充。所以如果能夠預測到你最終拼接的字符串大小,在初始化時不妨這樣寫:
StringBuilder sb = new StringBuilder(100);避免空間不足,反復開辟內存,影響效率。
ps:String作為常量,每次“+”都會生成新的對象,反復開辟內存,效率自然下降。
3)考慮到線程安全的情況,就要用到StringBuffer了,它的內部實現與StringBuilder類似,不過實現了數據同步,效率要低於StringBuilder。
五、字符串的比較
1、為空比較:
if(null == s || "".equals(s)){...}
把null==s放在左面以及""放在equals左邊,因為s有可能為null,直接造成程序空指針異常:java.lang.NullPointerException。
ps:另一種寫法,if(null==s||s.length()==0){...},話說這種效率要高於equals。
2.兩個對象進行比較
大多數情況下,我們關心的是字符串的值,而非內存地址,用equals進行比較。
在運行期,使用"=="進行字符串的比較,結果往往是不會讓你滿意的,有時會讓我們踩在坑裡好久好久,不停的問自己,為什麼這段邏輯始終不正確呢?因為永遠執行不到。
今天就寫到這裡,有沒有能觸動到你的地方呢?
關注老姜談技術,微信號:helojava,或者掃描下面二維碼。
每日一帖,技術雞湯。