淺談字符串比較

淺談字符串比較前一段時間自己想寫幾行代碼,所以就有了以下的代碼:

public
class TestString_1 {
public
static
void main(String[] args) {


String
str1="this is test";


String
str2="this is test";


String
str3=new
String("this is test");


String
str4=new
String("this is test");
System.out.println("str1==str2:"+(str1==str2));

System.out.println("str2==str3:"+(str2==str3));

System.out.println("str3==str4:"+(str3==str4));

}
}


運行結果是:

str1==str2:true
str2==str3:false
str3==str4:false


果然和我想的一樣。這樣就可以了。到時候和學生說str1str2是同一個HashCode,而str2str3不是同一個HashCode就可以了。哈哈!心中不由泛起對自己的崇拜。


爲了讓學生們更加的崇拜我。那就給他們show一下HashCode吧!在原有代碼的基礎上加了幾行輸出。(作死開始!)


System.out.println("str1==>"+str1.hashCode());


System.out.println("str2==>"+str2.hashCode());


System.out.println("str3==>"+str3.hashCode());


System.out.println("str4==>"+str4.hashCode());
可是輸出結果卻出人意料!!!
str1==>990854726
str2==>990854726
str3==>990854726
str4==>990854726



說好的HashCode不一樣呢?說好的HashCode是用優化地址算法的結晶,可是現在總是感覺自己在作夢一樣。爲什麼會這樣啊?
好吧,靜下心來先解決第一個問題!HashCode是怎麼來的。
在這裏,我們先不提及其它類。先來說一說String類。它的HashCode是自己覆寫了ObjectHashCode的方法。這段是從jdk1.7裏面找到的源碼。


public
int
hashCode() {

int
h = hash;//hash的值默認爲0

if (h == 0 && count > 0) {//count爲當前字符串的長度
//offset是字符串操作時的下標

int
off = offset;
//將當前字符串的值分割成字符數組

char
val[] = value;

int
len = count;



for (int
i = 0; i < leni++) {

h = 31*h + val[off++];
            }

hash = h;
        }

return
h;
}


好吧。這段代碼內我已經註釋了一部份。而最核心的那段for循環卻沒有解釋。這裏纔是Hash算法的體現之處。這裏面的h就是一個哈希值。是用累加上一次的h*31再加上當前字符的編碼值而算出來的。

可是什麼是HashCode?爲什麼要有這麼一段東西啊?

Hash其實是一種常用的數據結構。它的主要目的是對某組數據快速產生摘要。以方便大量數據之間進行對比。比方說我們常用的HashSet,在存儲數據的時候就可能會有這樣的需求。HashSet的存儲數據的特徵之一就是內容不重複。想要完成這樣的目的就會存在值的比較。數據量不足時,這種直接用值進行比較的方法還是可行的。但假設set內已經有1000條的情況下。使用 set.add(hi);單純進行值的比較就會有1000次的比較。這樣的工作效率很低。使用HashCode就不一樣了,比方說HashSet,底層是基於HashMap實現的,先通過HashCode取一個模,這樣一下子就固定到某個位置了,如果這個位置上沒有元素,那麼就可以肯定HashSet中必定沒有和新添加的元素equals的元素,就可以直接存放了,都不需要比較;如果這個位置上有元素了,逐一比較,比較的時候先比較HashCodeHashCode都不同接下去都不用比了,肯定不一樣,HashCode相等,再equals比較,沒有相同的元素就存,有相同的元素就不存。
所以我們知道了什麼是HashCode,以及它存在的意義,還有在JAVAStringHash算法了。那麼我們明白了一個道理。相同的字符串的HashCode一定相等。(因爲算法一致嘛)
那麼直接用str1.hashCode()去和str2.hashCode()比較不就可以驗證兩個字符串是否相等了?

我們再回頭看看之前的代碼。因爲代碼中的 h int類型的。當給出的值足夠長的情況下結果很可能會有溢出。那麼雖然重複的概率很少,但也一定有不同字符串的HashCode的值相同。
public
class TestString_2 {

public
static
void main(String[] args) {


String str1="重地";


String str2="通話";


System.out.println("str1==>"+str1.hashCode());


System.out.println("str2==>"+str2.hashCode());

}
}
輸出結果就是:
str1==>1179395
str2==>1179395

所以纔會有equals()方法。下面來看看Stringequals()方法的代碼
public
boolean equals(Object anObject) {


//比較兩個對象是否相同

if (this == anObject) {

return
true;
        }

//比較兩個對像是字符串類型

if (anObject
instanceof String) {
            String anotherString = (String)anObject;

//下面是將兩個對象內的值一一進行比較



int
n = count;

if (n == anotherString.count) {






char
v1[] = value;

char
v2[] = anotherString.value;






int
i = offset;

int
j = anotherString.offset;

while (n-- != 0) {

if (v1[i++] != v2[j++])

return
false;
                }

return
true;
            }
        }

return
false;
    }
通過上面的代碼,我們可以瞭解到。equals()方法有幾個步驟。
1判斷傳入對象的引用是否和當前對象相同,如果相同就直接返回true;
2判斷傳入對象是否屬於String類型,如果不同就直接返回false;
3判斷每個值與當前對象的值是否不同,如果不同就返回false;
4如果以上比較都沒有查出false那麼纔會返回true;


關於 == 的使用
==是容易理解的。java設計 == 就是要比較兩個對象引用的是不是同一個對象。
    對於引用變量而言,比較的時候兩個引用變量引用的是不是同一個對象,即比較的是兩個引用中存儲的對象地址是不是一樣的。
    對於基本數據類型而言,比較的就是兩個數據是不是相等,所以沒什麼歧義。


總結一下吧。
1比較對象的引用(即兩個引用是否同時引用同一對象時)用“==”。
2而比較兩個對象的值是否相等的時候,還是要使用equals()方法。
3HashCodeString類中只是通過value來給對象作出一個摘要來。方便快速比較的。

雖然爲自己開始的無知而感到害羞。但是通過一陣非常努力的折騰,最後我還是有點收穫的。心中泛起一丟丟地傲嬌。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章