關於Java中String你可能不知道的那些事


一.String的“==”和“equals”
private static void test1() {
Stringa = "a"+"b"+1;
Stringb = "ab1";
System.out.println(a== b );
}

上面這段代碼的輸出結果是true,可能有很多人知道結果,下面來解釋下原因。要解釋這個問題,我們需要知道這幾點。 1.關於"=="和equals是做什么的? 2.a和b在內存中是什么樣的? 3.編譯時優化方案。 "=="用於匹配內存單元上的內容,在Java語言中,"=="其實就是對比兩個內存單元的內容是否一樣,簡單說就是兩個對象的地址是否一樣。如果是基本類型,就是直接比較它們的值。如果是引用對象,比較的就是引用的值。引用的值可以被認為是對象的邏輯地址。如果兩個引用保存的對象是同一個對象,就返回true。 equals方法,在Object類中被定義的,默認就是"=="的實現,也就是說如果不覆寫equals方法,那么默認的equals就是對比對象的地址。 equals方法之所以存在,是希望子類去重寫這個方法,實現對比值的功能。類似的String就實現了equals方法。String的equals方法比較的是字符串的值是否相同。 重寫equals方法之后一定要重寫hashCode方法嗎?其實兩者之間沒有明確規定,但是一般都建議重寫hashCode方法,如果不重寫會在hashMap,HashSet中添加對象時出現意外的情況。 a和b的內存情況是什么樣的?上例中,a和b指的都是同一個對象"ab1"。這是在Java編譯器優化后產生的結果,當編譯器在編譯代碼Stringa="a"+"b"+1時會將其編譯為String a="ab1"為何?因為都是常量,編譯器認為這三個常量疊加會得到固定的值,無須運行時在計算,所以這樣優化,這樣做能一定的提升效率。所以上述a和b其實指的是同一個對象,這也說明了String的"+"操作不一定比StringBuilder.append方法慢。     
 private static String getA(){
return "a" ;
}
publicstatic void test2(){
Stringa = "a";
final String c = "a" ;
Stringb = a+"b";
Stringd = c+"b";
Stringe = getA()+"b";
Stringcompare = "ab";
System.out.println(b== compare );
System.out.println(d== compare );
System.out.println(e== compare );
}

上面說完之后繼續猜這段代碼,答案是false,true,false。這段代碼對於稍微有點復雜,結果不那么好猜,下面解釋下具體原因。 1.第一個輸出false,b與compare相比,compare是一個常量,那么b為什么不是呢?因為b=a+"b";a並不是一個常量,雖然a作為局部變量也指向一個常量,但是其引用並未約束是不可以改變的,雖然知道它在這段代碼不會改變,但運行時任何事情都會發生,在字節碼增強技術面前,當代碼發生切入后,就可能發生改變,所以編譯器不會做這樣的優化。 2.第二個輸出true,與第一個的區別在於對疊加的變量c有一個final修飾符,final修飾變量表示這個變量的引用不會改變,所以編譯器進行了優化。 3.第三個輸出false,這點和第一個相像,編譯器無法對方法進行有啊。 接下來討論下String的"=="和equals的區別,對於"=="只有兩個變量的引用指向相同的時候才返回true,即兩個String是一個對象,new String()產生的對象是不會相同的,而equals只要兩個String的值相同就會返回true,一般我們比較兩個字符串是否相等多會使用equals來比較。 附上String重寫的equals方法:  
public boolean equals(Object anObject ) {
if (this== anObject ) {
return true ;
}
if (anObject instanceof String) {
StringanotherString = (String) anObject;
int n = value .length;
if (n == anotherString .value .length ) {
char v1 [] = value ;
char v2 [] = anotherString .value;
int i = 0;
while (n -- != 0) {
if (v1 [i ] != v2 [i ])
return false ;
i++;
}
return true ;
}
}
return false ;
}

二.String的"+"和StringBuilder.append方法 很多書上說StringBuilder.append方法比String的"+"性能快很多,其實也不是絕對的,前面說過String的"+"操作時在拼接常量的時候是可以進行編譯器優化的,然而如果字符串不能被編譯器優化時,確實應該使用StringBuilder.append方法,String的"+"操作放在循環中,會創建出來無窮多的StringBuilder對象,並且執行append()后再調用toString()來生成一個新的String對象。這些臨時對象會占用大量的內存空間,導致頻繁的GC,這是String的"+"耗時的主要原因。 附上StringBuilder.append的實現  
public Abstract StringBuilder append(Stringstr) {
if (str == null)str = "null";
int len = str .length();
ensureCapacityInternal(count + len);
str.getChars(0,len,value,count);
count += len;
return this ;
}
void expandCapacity( intminimumCapacity ) {
int newCapacity = value .length* 2 + 2;
if (newCapacity - minimumCapacity< 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays. copyOf(value,newCapacity);
}



文章內容參考胖哥的Java特種兵,之前很幸運有機會和胖哥聊過一次,最近打算讀讀胖哥的書,長長見識。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: