String類的學習:
String a="a"+"b"+"1";
String b="ab1";
a==b是對的,為什麼
equals是Object類的方法,String類重寫了Object類的方法
而Object類中的equals方法用的就是==
JVM在編譯時會将常量提前計算好,比如int i= 3*4+11 在編譯的時候i的值已經被計算好了等于23了,在運作時是直接将23拿去運算的,同理,String a="a"+"b"+"1" 在編譯時String a已經變成"ab1"了,這是JVM的編譯優化,是以并不是所有的場景都是StringBuffer的append方法比String方法的+效率更好
但是JVM的編譯并不會将變量提前計算,例如
String a="a";
String b=a+"b";
String c="ab"
這個時候b==c是false,因為a是可變的,編譯不會優化,但如果a換成final String a = "a";時,情況又不一樣了,b==c是true
當a變成String a=new String("a")時,b==c又變成了false 是以确定JVM編譯優化的内容隻能是常量池中的對象
提到常量池,需要介紹String的一個intern方法,這個方法傳回的是對象在常量池中的位址,如果沒有找到,會建立等值的字元串,然後再傳回這個新字元串的的位址,是以當String b = a.intern()+"b";時,b==c是true
接下來我們來看String類型的equals方法的實作
public
boolean equals(ObjectanObject){
if (this ==
anObject) {
return
true;
}
if (anObject
instanceof String) {
String anotherString = (String)anObject;
int
n = value.length;
if (n ==
anotherString.value.length) {
char
v1[] = value;
v2[] = anotherString.value;
int
i = 0;
while (n-- != 0) {
if (v1[i] !=
v2[i])
return
false;
i++;
}
return
}
return
}
可以看到實作的步驟是先判斷是否為同一個對象,再判斷傳入的類型是否是String類型,接着判斷String類型的長度,再循環對比字元串的char[]數組,如果都比對,則傳回true,是以如果碰到很長的字元串需要到循環比對char[]數組的時候效率是非常慢的
接着我們來看StringBuffer的append和String 的+究竟如何使用
當String a="a";
String b=a+"b";
在編譯時,是編譯成StringBuilder temp = new StringBuilder();
tmp.append("a").append("b");
而StringBuilder的append方法和StringBuffer的append方法的實作都來自于AbstractStringBuilder
這裡實作方法的源碼就不看了
總結起來就是StringBuffer 最後.toString方法是最耗性能的,不要在需要在循環裡面使用StringBuffer對象的toString方法,會造成頻繁的GC
在循環中反而是String的+号性能更好
而在平時的字元串疊加中,使用StringBuffer的append方法一般至少不會比+号慢
String類的定義是final
classString
是以String類是不可變的,這樣在多線程的開發中String類是安全的,同時在初始化時,String的hashCode值會被緩存,作為Map的Key時字元串的處理會比其餘類型更快
當然String類還有很多方法,隻是挑了一些常見的去看,還待深入研究