摘要:如果我們不重寫(xiě)的方法,那么就會(huì)默認(rèn)調(diào)用的方法小王小王我們可以看到以上的運(yùn)行結(jié)果違背了的規(guī)定如果返回,那么方法必須返回相同的整數(shù)所以我們需要對(duì)對(duì)象的方法進(jìn)行重寫(xiě)通過(guò)重寫(xiě)讓其與對(duì)象的屬性關(guān)聯(lián)起來(lái),那么就能夠達(dá)到為,那么的值也相等。
面試官讓你說(shuō)說(shuō)==和equals()的區(qū)別,重寫(xiě)equals必須重寫(xiě)hashcode方法嗎
本身特質(zhì)來(lái)說(shuō)
==:操作符
equals():方法
適用對(duì)象
==:主要用于基本類(lèi)型之間的比較(char、Boolean、byte、short、int、long、float、dobule),也可以用于比較對(duì)象
equals():對(duì)象之間的比較(基本類(lèi)型的包裝器類(lèi)型,string,自己定義的對(duì)象等)
比較對(duì)象時(shí)的區(qū)別
==:比較兩個(gè)對(duì)象是否指向同一個(gè)對(duì)象,也就是說(shuō)他們指向的對(duì)象的首地址是否相同
equals():可以通過(guò)重寫(xiě)equals方法從而比較對(duì)象的內(nèi)容是否相同,如果不重寫(xiě)那么和==符號(hào)沒(méi)有區(qū)別,都是比較的對(duì)象的引用是否指向同一個(gè)對(duì)象
對(duì)于一個(gè)對(duì)象student來(lái)說(shuō),如果我們不重寫(xiě)它的equals方法,那么和==符號(hào)一樣比較的是對(duì)象的引用而不是內(nèi)容
public class Student { private int id; private String name; private String password; public Student(int id, String name, String password) { this.id = id; this.name = name; this.password = password; } }
public class Test2 { public static void main(String[] args){ Student s1 = new Student(1, "小王", "123456"); Student s2 = new Student(1, "小王", "123456"); System.out.println(s1 == s2);//false System.out.println(s1.equals(s2));//false } }
上面兩個(gè)對(duì)象s1和s2不相等,因?yàn)樗麄冎赶虻氖莾蓚€(gè)不同的對(duì)象,所以引用不同,但是我們的目的是要達(dá)到如果id,name,password都相同,那么就是同一個(gè)對(duì)象,所以需要重寫(xiě)equals()方法
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (id != student.id) return false; if (name != null ? !name.equals(student.name) : student.name != null) return false; return password != null ? password.equals(student.password) : student.password == null; }
這個(gè)時(shí)候我們?cè)龠\(yùn)行
public class Test2 { public static void main(String[] args){ Student s1 = new Student(1, "小王", "123456"); Student s2 = new Student(1, "小王", "123456"); System.out.println(s1 == s2);//false System.out.println(s1.equals(s2));//true } }
對(duì)于string類(lèi)型來(lái)說(shuō),它的的equals()方法是對(duì)object方法的equals()進(jìn)行了重寫(xiě),從而比較的字符串序列是
否相同如下:
String s1 = new String("abc");//s1存在于堆內(nèi)存中 String s2 = new String("abc");//s2也存在于堆內(nèi)存中 System.out.println(s1 == s2);//false s1和s2指向的對(duì)象的首地址不一樣,不是同一個(gè)對(duì)象 System.out.println(s1.equals(s2));//true s1和s2指向的對(duì)象的內(nèi)容相同
ps:
String s3 = "abc"; String s4 = "abc"; System.out.println(s3 == s4);//true System.out.println(s3.equals(s4));//true
接下來(lái)我們討論一下重寫(xiě)equals()方法的同時(shí)必須要重寫(xiě)hashcode()方法嗎
? 首先我們重寫(xiě)equals()的目的就是為了讓內(nèi)容相同的對(duì)象讓它們相同,而不是單單只比較對(duì)象的引用(對(duì)象的首地址),也就是盡管這兩個(gè)對(duì)象的引用地址不同,但是我們調(diào)用equals方法的時(shí)候仍然返回true
? 那么這個(gè)時(shí)候我們?yōu)槭裁从忠貙?xiě)hashcode方法呢,hashcode()返回的是對(duì)象的地址,是一個(gè)散列值,那么如果我們通過(guò)equals()方法得到這兩個(gè)對(duì)象相同,盡管他們?cè)诙阎械膬?nèi)存地址不一樣,但是我們希望他們的哈希值是一樣的,這樣如果存入map的話(huà),就能定位到相同的索引
? 同時(shí)Java標(biāo)準(zhǔn)中對(duì)hashcode有如下的規(guī)定:
在java應(yīng)用程序執(zhí)行期間,如果在equals方法比較中所用的信息沒(méi)有被修改,那么在同一個(gè)對(duì)象上多次調(diào)用hashCode方法時(shí)必須一致地返回相同的整數(shù)。如果多次執(zhí)行同一個(gè)應(yīng)用時(shí),不要求該整數(shù)必須相同。
如果兩個(gè)對(duì)象通過(guò)調(diào)用equals方法是相等的,那么這兩個(gè)對(duì)象調(diào)用hashCode方法必須返回相同的整數(shù)。
如果兩個(gè)對(duì)象通過(guò)調(diào)用equals方法是不相等的,不要求這兩個(gè)對(duì)象調(diào)用hashCode方法必須返回不同的整數(shù)。
如果我們不重寫(xiě)student的hashcode()方法,那么就會(huì)默認(rèn)調(diào)用object的hashcode()方法:
public class Test2 { public static void main(String[] args){ Student s1 = new Student(1, "小王", "123456"); Student s2 = new Student(1, "小王", "123456"); System.out.println(s1 == s2);//false System.out.println(s1.equals(s2));//true System.out.println(s1.hashCode());//356573597 System.out.println(s2.hashCode());//1735600054 } }
我們可以看到以上的運(yùn)行結(jié)果違背了hashcode的規(guī)定:如果equals()返回true,那么hashcode方法必須返回相同的整數(shù)
所以我們需要對(duì)student對(duì)象的hashcode方法進(jìn)行重寫(xiě)
@Override public int hashCode() { int result = id; result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + (password != null ? password.hashCode() : 0); return result; }
通過(guò)重寫(xiě)hashcode()讓其與對(duì)象的屬性關(guān)聯(lián)起來(lái),那么就能夠達(dá)到equals()為true,那么hashcode的值也相等。
現(xiàn)在我們已經(jīng)知道了重寫(xiě)equals()方法的同時(shí)需要重寫(xiě)對(duì)象的hashcode()方法,讓其滿(mǎn)足hashcode的標(biāo)準(zhǔn)條件。
? 但是好奇的同學(xué)可能會(huì)想到:為什么hashcode需要這樣定義標(biāo)準(zhǔn)呢,這樣做到底有什么好處呢,除了讓equals()方法和hashcode()方法的返回值具有一致性。
這時(shí)我們就需要提到map類(lèi)了,我們知道hashmap的結(jié)構(gòu)是一個(gè)數(shù)組加鏈表組成的,我們通過(guò)key的
? hashcode % hashmap的capacity 定位到具體數(shù)組的索引,然后將該(key,value)放入該索引對(duì)應(yīng)的鏈表里面,這里之所以為鏈表就是為了解決hash沖突,即hashcode % capacity 相同的值有很多,需要用一個(gè)鏈表存儲(chǔ)起來(lái),如果想要鏈表短一點(diǎn),也就是hash沖突少一點(diǎn),那么就需要減小hashmap的負(fù)載因子loadFacotor,當(dāng)然這里也就扯遠(yuǎn)了,我們繼續(xù)回到正題,
Student s1 = new Student(1, "小王", "123456"); Student s2 = new Student(1, "小王", "123456");
? 對(duì)于s1和s2兩個(gè)對(duì)象,如果我們我們已經(jīng)將s1存入一個(gè)map對(duì)象,那么我們?cè)俅嫒雜2時(shí),我們希望的是這是不能再插入map了,因?yàn)榇藭r(shí)map中已經(jīng)存在小王這個(gè)對(duì)象了,那么如何才能做到呢
? 首先我們通過(guò)s1的hashcode % capacity 得到了一個(gè)數(shù)組索引,然后將s1這個(gè)對(duì)象存入map,那么我們?cè)俨迦雜2的時(shí)候同樣也需要計(jì)算它的hashcode,然后定位到相同的數(shù)組索引,然后判斷該鏈表中是否存在小王這樣一個(gè)對(duì)象,如果存在就不put
? 所以我們需要得到的s1和s2的hashcode相同,才能避免同一個(gè)對(duì)象被put進(jìn)入map中多次,所以我們才需要在重寫(xiě)equals()方法的同時(shí)重寫(xiě)equals()方法,讓兩個(gè)相等的對(duì)象具有相同的hashcode
? 可能細(xì)心的盆友會(huì)發(fā)現(xiàn)如果我們只是需要簡(jiǎn)單的根據(jù)判斷兩個(gè)對(duì)象的內(nèi)容是否相同來(lái)判斷兩個(gè)對(duì)象是否相等,而不涉及到ma"p操作,那么其實(shí)也是不用重寫(xiě)ha"shcode方法了,但是萬(wàn)一哪天突然不小心放進(jìn)了map了呢,所以一般我們重寫(xiě)equals()方法的同時(shí)都會(huì)重寫(xiě)hashcode(),確保萬(wàn)無(wú)一失~
參考
重寫(xiě)equal()時(shí)為什么也得重寫(xiě)hashCode()之深度解讀equal方法與hashCode方法淵源
重寫(xiě)equals方法后重寫(xiě)hashCode方法的必要性
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/77773.html
摘要:介紹的作用是獲取哈希碼,也稱(chēng)為散列碼它實(shí)際上是返回一個(gè)整數(shù)。所以具有相索引的對(duì)象,在該散列碼位置處存在多個(gè)對(duì)象,我們必須依靠的和本身來(lái)進(jìn)行區(qū)分。 1.hashCode介紹 hashCode() 的作用是獲取哈希碼,也稱(chēng)為散列碼;它實(shí)際上是返回一個(gè)int整數(shù)。這個(gè)散列碼的作用是確定該對(duì)象在散列表中的索引位置,如果有看我的上一篇文章 什么是散列表,那么這里的散列碼就相當(dāng)于上文中根據(jù)首字母查...
摘要:中,任何未處理的受檢查異常強(qiáng)制在子句中聲明。運(yùn)行時(shí)多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)需要方法重寫(xiě)子類(lèi)繼承父類(lèi)并重寫(xiě)父類(lèi)中已 1、簡(jiǎn)述Java程序編譯和運(yùn)行的過(guò)程:答:① Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼,創(chuàng)建完源文件之后,程序會(huì)先被編譯成 .class 文件。② 在編譯好的java程序得到.class文件后,使用命令java 運(yùn)行這個(gè) .c...
摘要:中,任何未處理的受檢查異常強(qiáng)制在子句中聲明。運(yùn)行時(shí)多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)需要方法重寫(xiě)子類(lèi)繼承父類(lèi)并重寫(xiě)父類(lèi)中已 1、簡(jiǎn)述Java程序編譯和運(yùn)行的過(guò)程:答:① Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼,創(chuàng)建完源文件之后,程序會(huì)先被編譯成 .class 文件。② 在編譯好的java程序得到.class文件后,使用命令java 運(yùn)行這個(gè) .c...
摘要:最近看到上面的一篇博客面試必備最常見(jiàn)的面試題全解析講解了關(guān)于體系的一些模塊以及面試中的一些常見(jiàn)問(wèn)題雖然最近沒(méi)有要去找工作的需求但是鞏固一下這方面的知識(shí)還是很有必要的后面從作者提出的問(wèn)題進(jìn)行自我的提問(wèn)與解答有問(wèn)題歡迎大家指出基礎(chǔ)部分和的區(qū)別我 最近看到CSDN上面的一篇博客 面試必備:《Java最常見(jiàn)的200+面試題全解析》, 講解了關(guān)于Java體系的一些模塊以及面試中的一些常見(jiàn)問(wèn)題; ...
摘要:在中對(duì)象是一切對(duì)象都會(huì)自動(dòng)繼承的一個(gè)類(lèi),在這個(gè)類(lèi)中定義的屬性和方法可以說(shuō)是每個(gè)類(lèi)都必須的。這里有必要說(shuō)說(shuō)這里對(duì)象里面的幾個(gè)方法返回該對(duì)象的哈希碼值。這些基于表的集合,只能要求被存放的對(duì)象實(shí)現(xiàn)自己的方法,保證的均勻性。 Object 在Java中Object對(duì)象是一切對(duì)象都會(huì)自動(dòng)繼承的一個(gè)類(lèi),在這個(gè)類(lèi)中定義的屬性和方法可以說(shuō)是每個(gè)類(lèi)都必須的。 這里有必要說(shuō)說(shuō)這里對(duì)象里面的幾個(gè)方法 has...
閱讀 2047·2021-11-22 09:34
閱讀 1240·2021-10-09 09:44
閱讀 3095·2021-09-29 09:35
閱讀 3684·2021-09-14 18:01
閱讀 1562·2021-08-16 10:49
閱讀 1168·2019-08-29 14:11
閱讀 906·2019-08-29 12:47
閱讀 3135·2019-08-26 13:47