重寫eques后重寫hashCode必要性

1、首先我們看看對象默認的(Object)的equals方法和hashcode方法

public boolean equals(Object obj) {

return(this== obj);

}

public native int hashCode();

對象在不重寫的情況下使用的是Object的equals方法和hashcode方法,從Object類的源碼我們知道,默認的equals 判斷的是兩個對象的引用指向的是不是同一個對象;而hashcode也是根據對象地址生成一個整數數值;



2、重寫equals

案例場景:

定義一個User對象有多個屬性值姓名、年齡、身份證;

我們寫代碼的時候會發現,兩個new出來的User()對象 無論他們的的各項值是否一樣兩個對象equals永遠都是false,兩個對象值完全一樣放到HashSet里面它會把這兩個值完全一樣的對象當成兩個不同的對象了,這樣的話好像HashSet的特性就丟失了;

其實原因就是我們沒有重寫User的equals方法,它會調用Object的equals方法,就如上圖一樣,Object的equals方法是比較對象的引用對象是否是同一個,兩個new出來的對象當然不一樣。

好了現在需求來了,我們需要兩個對象的各項屬性值一樣的就認為這兩個對象是相等的;那么此時我們就需要重寫equals方法了;

代碼如下

public classUser {

privateStringname;//姓名

privateStringIdCard;//身份證

private intage;//年齡

/**

* 重寫equals

*@paramobj

*@return

*/

@Override

@Override

public boolean equals(Object obj) {

if(obj ?instanceof ?User) {

User user = (User) obj;

if(user.getIdCard().equals(this.IdCard) && user.getName().equals(this.name) && user.getAge() ==this.age) {

return true;

}else{

return false;

}

}else{

return false;

}

}

//......省略N行代碼

}

那么現在關鍵的地方來了:現在我們重寫了User對象的equals方法,但并沒有重寫hashcode方法。

(1)首先測試下equals的正確性

User user1=newUser();

user1.setName("路西");

user1.setAge(18);

user1.setIdCard("430");

User user2=newUser();

user2.setName("路西");

user2.setAge(18);

user2.setIdCard("430");

System.out.println("user1.equals(user2)="+user1.equals(user2));

user1.equals(user2)測試結果為true;

(2)在兩個對象equals的情況下進行把他們分別放入Map和Set中

在上面的代碼基礎上追加如下代碼:

Set set =newHashSet();

set.add(user1);

set.add(user2);

Map map=newHashMap();

map.put(user1,"user1");

map.put(user2,"user2");

System.out.println("set 長度"+set.size());

System.out.println("map 長度"+map.keySet().size());;

測試打印結果為:


好了現在問題來了,明明user1和user2兩個對象是equals的那么為什么把他們放到set中會有兩個對象(Set特性是不允許重復數據的),還有Map也把兩個同樣的對象當成了不同的Key(Map的Key是不允許重復的,相同Key會覆蓋);

(3)這里我先拋出結果,至于原理后面再進行描述

原因是user1和user2的hashcode 不一樣導致的;



因為我們沒有重寫父類(Object)的hashcode方法,Object的hashcode方法會根據兩個對象的地址生成對相應的hashcode;

user1和user2是分別new出來的,那么他們的地址肯定是不一樣的,自然hashcode值也會不一樣。

Set區別對象是不是唯一的標準是,兩個對象hashcode是不是一樣,再判定兩個對象是否equals;

Map 是先根據Key值的hashcode分配和獲取對象保存數組下標的,然后再根據equals區分唯一值(詳見下面的map分析)


3、重寫hashcode方法;

public classUser? {

privateStringname;//姓名

privateStringIdCard;//身份證

private intage;//年齡

* 重寫equals

*@paramobj

*@return

*/

@Override

public boolean equals(Object obj) {

if(obj ?instanceof ?User) {

User user = (User) obj;

if(user.getIdCard().equals(this.IdCard) && user.getName().equals(this.name) && user.getAge() ==this.age) {

return true;

}else{

return false;

}

}else{

return false;

}

}

@Override

public int hashCode() {

intresult =name.hashCode();

result =31* result +IdCard.hashCode();

result =31* result +age;

returnresult;

}

//......省略N行代碼

}

我們按之前的流程重新測試一遍結果:

User user1=newUser();

user1.setName("路西");

user1.setAge(18);

user1.setIdCard("430");

User user2=newUser();

user2.setName("路西");

user2.setAge(18);

user2.setIdCard("430");

System.out.println("user1.equals(user2)="+user1.equals(user2));

Set set =newHashSet();

set.add(user1);

set.add(user2);

Map map=newHashMap();

map.put(user1,"user1");

map.put(user2,"user2");

System.out.println("set 長度"+set.size());

System.out.println("map 長度"+map.keySet().size());;

System.out.println("user1的hashcode"+user1.hashCode());

System.out.println("user2的hashcode"+user2.hashCode());

打印結果:



4、補充HashMap知識

hashMap組成結構:hashMap是由數組和鏈表組成;

hashMap的存儲:一個對象存儲到hashMap中的位置是由其key 的hashcode值決定的;查hashMap查找key: 找key的時候hashMap會先根據key值的hashcode經過取余算法定位其所在數組的位置,再根據key的equals方法匹配相同key值獲取對應相應的對象;

案例:

(1)hashmap存儲

存值規則:把Key的hashCode 與HashMap的容量 取余得出該Key存儲在數組所在位置的下標(源碼定位Key存儲在數組的哪個位置是以hashCode & (HashMap容量-1)算法得出)這里為方便理解使用此方式;

//為了演示方便定義一個容量大小為3的hashMap(其默認為16)

HashMap map=newHashMap(3);

map.put("a",1);? ? 得到key 為“a” 的hashcode 值為97然后根據 該值和hashMap 容量取余97%3得到存儲位到數組下標為1;

map.put("b",2);? ? 得到key 為“b” 的hashcode 值為98,98%3到存儲位到數組下標為2;

map.put("c",3);? ? 得到key 為“c” 的hashcode 值為99,99%3到存儲位到數組下標為0;

map.put("d",4);? ? 得到key 為“d” 的hashcode 值為100,100%3到存儲位到數組下標為1;

map.put("e",5);? ? 得到key 為“e” 的hashcode 值為101,101%3到存儲位到數組下標為2;

map.put("f",6);? ? 得到key 為“f” 的hashcode 值為102,102%3到存儲位到數組下標為0;



(2)hashmap的查找key

得到key在數組中的位置:根據上圖,當我們獲取key 為“a”的對象時,那么我們首先獲得 key的hashcode97%3得到存儲位到數組下標為1;

匹配得到對應key值對象:得到數組下表為1的數據“a”和“c”對象, 然后再根據 key.equals()來匹配獲取對應key的數據對象;

hashcode 對于HashMapde:如果沒有hashcode 就意味著HashMap存儲的時候是沒有規律可尋的,那么每當我們map.get()方法的時候,就要把map里面的對象一一拿出來進行equals匹配,這樣效率是不是會超級慢;


5、hashcode方法文檔說明

在equals方法沒被修改的前提下,多次調用同一對象的hashcode方法返回的值必須是相同的整數;

如果兩個對象互相equals,那么這兩個對象的hashcode值必須相等;

為不同對象生成不同的hashcode可以提升哈希表的性能;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,714評論 18 399
  • 實際上,HashSet 和 HashMap 之間有很多相似之處,對于 HashSet 而言,系統采用 Hash 算...
    曹振華閱讀 2,515評論 1 37
  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,508評論 0 3
  • 一、基本數據類型 注釋 單行注釋:// 區域注釋:/* */ 文檔注釋:/** */ 數值 對于byte類型而言...
    龍貓小爺閱讀 4,282評論 0 16
  • 謹以此文獻給我們最美麗的十八歲。 大二。計科男。北方燥熱的城市。日子過得像最藍的天空,最白的云,波...
    相機信紙棋閱讀 288評論 2 2