重寫eques后重寫hashCode必要性

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

public boolean equals(Object obj) {

return(this== obj);

}

public native int hashCode();

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



2、重寫equals

案例場(chǎng)景:

定義一個(gè)User對(duì)象有多個(gè)屬性值姓名、年齡、身份證;

我們寫代碼的時(shí)候會(huì)發(fā)現(xiàn),兩個(gè)new出來(lái)的User()對(duì)象 無(wú)論他們的的各項(xiàng)值是否一樣兩個(gè)對(duì)象equals永遠(yuǎn)都是false,兩個(gè)對(duì)象值完全一樣放到HashSet里面它會(huì)把這兩個(gè)值完全一樣的對(duì)象當(dāng)成兩個(gè)不同的對(duì)象了,這樣的話好像HashSet的特性就丟失了;

其實(shí)原因就是我們沒(méi)有重寫User的equals方法,它會(huì)調(diào)用Object的equals方法,就如上圖一樣,Object的equals方法是比較對(duì)象的引用對(duì)象是否是同一個(gè),兩個(gè)new出來(lái)的對(duì)象當(dāng)然不一樣。

好了現(xiàn)在需求來(lái)了,我們需要兩個(gè)對(duì)象的各項(xiàng)屬性值一樣的就認(rèn)為這兩個(gè)對(duì)象是相等的;那么此時(shí)我們就需要重寫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行代碼

}

那么現(xiàn)在關(guān)鍵的地方來(lái)了:現(xiàn)在我們重寫了User對(duì)象的equals方法,但并沒(méi)有重寫hashcode方法。

(1)首先測(cè)試下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)測(cè)試結(jié)果為true;

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

在上面的代碼基礎(chǔ)上追加如下代碼:

Set set =newHashSet();

set.add(user1);

set.add(user2);

Map map=newHashMap();

map.put(user1,"user1");

map.put(user2,"user2");

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

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

測(cè)試打印結(jié)果為:


好了現(xiàn)在問(wèn)題來(lái)了,明明user1和user2兩個(gè)對(duì)象是equals的那么為什么把他們放到set中會(huì)有兩個(gè)對(duì)象(Set特性是不允許重復(fù)數(shù)據(jù)的),還有Map也把兩個(gè)同樣的對(duì)象當(dāng)成了不同的Key(Map的Key是不允許重復(fù)的,相同Key會(huì)覆蓋);

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

原因是user1和user2的hashcode 不一樣導(dǎo)致的;



因?yàn)槲覀儧](méi)有重寫父類(Object)的hashcode方法,Object的hashcode方法會(huì)根據(jù)兩個(gè)對(duì)象的地址生成對(duì)相應(yīng)的hashcode;

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

Set區(qū)別對(duì)象是不是唯一的標(biāo)準(zhǔn)是,兩個(gè)對(duì)象hashcode是不是一樣,再判定兩個(gè)對(duì)象是否equals;

Map 是先根據(jù)Key值的hashcode分配和獲取對(duì)象保存數(shù)組下標(biāo)的,然后再根據(jù)equals區(qū)分唯一值(詳見(jiàn)下面的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行代碼

}

我們按之前的流程重新測(cè)試一遍結(jié)果:

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 長(zhǎng)度"+set.size());

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

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

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

打印結(jié)果:



4、補(bǔ)充HashMap知識(shí)

hashMap組成結(jié)構(gòu):hashMap是由數(shù)組和鏈表組成;

hashMap的存儲(chǔ):一個(gè)對(duì)象存儲(chǔ)到hashMap中的位置是由其key 的hashcode值決定的;查hashMap查找key: 找key的時(shí)候hashMap會(huì)先根據(jù)key值的hashcode經(jīng)過(guò)取余算法定位其所在數(shù)組的位置,再根據(jù)key的equals方法匹配相同key值獲取對(duì)應(yīng)相應(yīng)的對(duì)象;

案例:

(1)hashmap存儲(chǔ)

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

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

HashMap map=newHashMap(3);

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

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

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

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

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

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



(2)hashmap的查找key

得到key在數(shù)組中的位置:根據(jù)上圖,當(dāng)我們獲取key 為“a”的對(duì)象時(shí),那么我們首先獲得 key的hashcode97%3得到存儲(chǔ)位到數(shù)組下標(biāo)為1;

匹配得到對(duì)應(yīng)key值對(duì)象:得到數(shù)組下表為1的數(shù)據(jù)“a”和“c”對(duì)象, 然后再根據(jù) key.equals()來(lái)匹配獲取對(duì)應(yīng)key的數(shù)據(jù)對(duì)象;

hashcode 對(duì)于HashMapde:如果沒(méi)有hashcode 就意味著HashMap存儲(chǔ)的時(shí)候是沒(méi)有規(guī)律可尋的,那么每當(dāng)我們map.get()方法的時(shí)候,就要把map里面的對(duì)象一一拿出來(lái)進(jìn)行equals匹配,這樣效率是不是會(huì)超級(jí)慢;


5、hashcode方法文檔說(shuō)明

在equals方法沒(méi)被修改的前提下,多次調(diào)用同一對(duì)象的hashcode方法返回的值必須是相同的整數(shù);

如果兩個(gè)對(duì)象互相equals,那么這兩個(gè)對(duì)象的hashcode值必須相等;

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,652評(píng)論 18 399
  • 實(shí)際上,HashSet 和 HashMap 之間有很多相似之處,對(duì)于 HashSet 而言,系統(tǒng)采用 Hash 算...
    曹振華閱讀 2,561評(píng)論 1 37
  • java筆記第一天 == 和 equals ==比較的比較的是兩個(gè)變量的值是否相等,對(duì)于引用型變量表示的是兩個(gè)變量...
    jmychou閱讀 1,645評(píng)論 0 3
  • 一、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對(duì)于byte類型而言...
    龍貓小爺閱讀 4,443評(píng)論 0 16
  • 謹(jǐn)以此文獻(xiàn)給我們最美麗的十八歲。 大二。計(jì)科男。北方燥熱的城市。日子過(guò)得像最藍(lán)的天空,最白的云,波...
    相機(jī)信紙棋閱讀 306評(píng)論 2 2

友情鏈接更多精彩內(nèi)容