最近看javaSe基礎,被String類的equals方法和“==”搞懵逼了,類似的題目總是搞不到,覺得好好花點時間把這個問題搞清楚,寫下自己的心得。如有錯誤,還望各位指正!
一、String類生成對象的內存問題。
字符串在內存通常分配在內存的兩個位置,一個是常量區,一個是在堆內存中。
第一種形式: String str ="abc";
這句話是在字符串常量區創建一個“abc”的對象,str爲這個對象的引用。如果再來一句String str2 =“abc”,這是JVM並不是重新又創建一個新的對象,而是先在字符串常量池中看有沒有這個對象,若有,將str2指向字符串“abc”;若沒有才會重新創建。我們可以通過System.out.println(str1==str2)來判斷str1和str2是指向同一個引用。
類似String s ="abc"+“edf”也經常碰見。s 也是在字符串常量池中。JVM會先在字符串常量池中查找字符串“abc”和“edf”,沒有則重新創建,有則直接引用,然後會在字符串常量池中生成新的字符串“abcedf”;
第二種形式:String s =new String("abc");
這種形式是利用String類的構造器方法在堆內存中創建對象。JVM 首先會在字符串常量池中找“abc",有則直接引用,沒有則創建。然後將該對象複製到堆內存中。s指向該對象的內存。由於堆內存中的每個對象內存地址不同,所以String s1 =new String("abc")
和String s2=new String("abc")是兩個不同的對象,我們用System.out.println(s1==s2)可以判斷它們是兩個不同的對象。
二、equals方法和== 的區別。
“==”是直接比較兩個對象的地址。我們上面判斷字符串是否是同一個對象就是用的“==”方法。equals方法是Object對象的方法,我們可以看下Object類中equals方法的源碼:
public boolean equals(Object obj) {
return (this == obj);
}
我們可以看到,它其實就是調用了“==”,Object對象的equals方法就是比較兩個對象的內存地址,相同返回true,否則返回false。而String類是Object類的之類,但是String類繼承Object類之後重寫了它的equals方法,源碼如下:
public boolean equals(Object anObject) {
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;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
我們可以看到,String類也是先比較兩個對象的地址,地址相同則直接返回true,如果不相同,則將傳入的對象轉換成字符串,再開始進行內容的比較,所以String類的equals方法我們可以認爲它是比較字符串的內容的。同理我們可以發現很多類都重寫了Object類的equals方法,那麼這時候的equals方法可能就不是比較對象的地址了。
總結:String類的對象一般存儲在字符串常量池和堆內存中,其中用new關鍵字的創建的對象在堆內存中。“==”是比較兩個對象的內存地址,Object類對象的equals方法就是比較對象的內存地址。由於Object類爲一切類的父類,所以如果類沒有重寫equals方法,那麼相當於它是調用的Object類的equals方法,比較的是對象的內存地址。重寫了Object類的equals方法的類,該方法比較的內容就要看具體的實現了。