我們知道,equals()函數(shù)是用來(lái)做比較的。java中的比較有兩種:一種是內(nèi)存地址的比較,一種是內(nèi)容的比較。而比較個(gè)體也有兩種:一種是簡(jiǎn)單類型(這類簡(jiǎn)單說(shuō)來(lái)無(wú)所謂內(nèi)存地址的比較或者內(nèi)容比較的區(qū)別);還有一種是對(duì)象的比較,本文中說(shuō)的主要是后者

在java中,(對(duì)象)內(nèi)存地址的比較,是通過(guò)==完成的。比如 

if (obj1  ==  obj2) {
    ...
}

這樣的語(yǔ)句中,我們認(rèn)為,如果obj1和obj2的內(nèi)存地址相同,則返回true

而equals()通常是比較內(nèi)容的。這里說(shuō)“通常” ,是因?yàn)樵谧罡镜腛bject類中,equal()函數(shù)做的是地址的比較。而在其他幾乎所有的類中,equals()都經(jīng)過(guò)重載,進(jìn)行內(nèi)容的比較。

而在說(shuō)equals()的時(shí)候我們還涉及hashCode()是因?yàn)樵谟行?yīng)用中(比如,HashMap的key是對(duì)象),必須在重載equals()的同時(shí)重載hashCode()。因?yàn)閖ava中默認(rèn)(Object)的hashCode是根據(jù)對(duì)象的地址計(jì)算得到的。

我們通常不會(huì)注意到這個(gè)問(wèn)題,因?yàn)槲覀兺ǔK褂玫?em>key都是簡(jiǎn)單類型,或者是String, Long等一些特殊的對(duì)象(其特殊性請(qǐng)參看筆者在寫java 淺拷貝和深拷貝時(shí)的討論),這時(shí)候,這個(gè)問(wèn)題被我們無(wú)意間繞過(guò)了

有人已經(jīng)概括了這種我們忽略了的情況:“如果你想將一個(gè)對(duì)象A放入另一個(gè)收集(集合)對(duì)象B里,或者使用這個(gè)對(duì)象A為查找一個(gè)元對(duì)象在收集對(duì) 象B里位置的鑰匙(key),并支持是否容納(isContains()),刪除收集對(duì)象B里的元對(duì)象(remove()?)這樣的操作,那么,equals()和hashCode()函數(shù)必須開發(fā)者自己定義。” (括號(hào)為筆者添加)

為了便于理解,舉一段程序?yàn)槔?/p>

import  java.util. * ;
public   class  Person {

int  id;
String name;

// define getter and setter here, omited

public  Person( int  id, String name) {
     
this .id  =  id;
     
this .name  =  name;
     
}


public   boolean  equals(Object o) {
       
if ( this == o)  return   true ;
    
if (o  instanceof  Person)
    
return  ( this .id  ==  ((Person)o).id)  &&  ( this .name.equals(((Person)o).name));
    }


/*          
public int hashCode(){
    return id*37;
}
*/


public   static   void  main(String args[])  {
    Person p1 
=   new  Person( 1 , " aaa " );
    Person p2 
=   new  Person( 1 , " aaa " );
    Map map 
=   new  HashMap();

    map.put(p2,p1);
    Person value 
=  (Person)map.get(p1);
    System.out.println(value.name);
  }

}

這段代碼的結(jié)果是什么?答案是nullPointerExcetpion.

而把hashCode()的注釋去除,程序就可以返回正確的結(jié)果了。為什么呢?因?yàn)椋?/p>

Map.put(key,value)時(shí)根據(jù)key.hashCode生成一個(gè)內(nèi)部hash值,根據(jù)這個(gè)hash值將對(duì)象存放在一個(gè)table中

Map.get(key)會(huì)比較key.hashCode和equals方法,當(dāng)且僅當(dāng)這兩者相等時(shí),才能正確定位到table。而我們說(shuō)過(guò),默認(rèn)的java是對(duì)地址進(jìn)行比較的。