“==”
首先要講下Java中的數(shù)據(jù)類型,分為倆類
基本數(shù)據(jù)類型(或者叫值類型、也叫原始數(shù)據(jù)類型),比如byte、int、double、boolean等,他們之間的比較就是使用“==”,這時(shí)候?qū)Ρ鹊氖撬麄兊闹凳欠裣嗟?/p>
int a = 10;
int b = 10;
System.out.print("a==b? " + (a == b));
//輸出結(jié)果 a==b? true
引用數(shù)據(jù)類型,比如數(shù)組、類、接口等,這些數(shù)據(jù)直接使用“==”的話,進(jìn)行比對(duì)的是其引用地址是否相同(這里對(duì)于String的比較后面再分析)
Integer aObj = new Integer(10);
Integer bObj = new Integer(10);
System.out.print("aObj==bObj? "+(aObj == bObj));
//輸出結(jié)果?aObj==bObj? false
下面我們對(duì)“==”比較的一些情況進(jìn)行分析,大家都看到了,我們用到了Integer,有必要跟大家說一下這個(gè)Integer是什么,這就要涉及到Java中的另一個(gè)概念了,包裝類,每中基本數(shù)據(jù)類型都會(huì)對(duì)應(yīng)有一個(gè)包裝類,為了讓基本數(shù)據(jù)類型也能滿足萬事萬物皆對(duì)象嘛,其實(shí)包裝類的出現(xiàn)對(duì)我們的很多操作都方便了。說到它那就得說它的2個(gè)概念,封箱和拆箱,簡單解釋就是,將基本數(shù)據(jù)類型封箱成對(duì)應(yīng)的包裝類,拆箱就是將包裝類轉(zhuǎn)換成對(duì)應(yīng)的基本類型。
說了這么個(gè)概念,那到底對(duì)我們理解“==”有什么用呢?下面看下基本類型與包裝類之間的相互比較的結(jié)果:
Integer aObj = new Integer(10);
Integer bObj = 100;
Integer cObj = 100;
int a = 10;
int b = 100;
System.out.println("aObj==a? " + (aObj == a)); //true
System.out.println("bObj==cObj? " + (bObj == cObj));?//true
System.out.println("bObj==b? " + (bObj == b)); //true 與第一個(gè)含義相同
對(duì)于上面的結(jié)果分析:
第一個(gè) aObj == a 為true,那是因?yàn)榛緮?shù)據(jù)類型與對(duì)應(yīng)的包裝類對(duì)象進(jìn)行“==”比較的時(shí)候,包裝類型會(huì)進(jìn)行自動(dòng)拆箱操作,拆箱成基本數(shù)據(jù)類型,所以最終比較的還是他們的值。
第二個(gè) bObj == cObj 為true,這其中的原由要牽扯到Java編譯,Java在編譯的時(shí)候會(huì)對(duì)包裝類型賦值基本數(shù)據(jù)轉(zhuǎn)換成Integer.valueOf(基本數(shù)據(jù)); 也就是說??Integer bObj = 100;在class文件里面的含義就變成了?Integer bObj = Integer.valueOf(100);大家可以點(diǎn)進(jìn)去看下valueOf的源碼:

通過源碼可知,對(duì)于-128到127之間的數(shù),Java會(huì)進(jìn)行緩存,Integer bObj = 100;時(shí),會(huì)將100進(jìn)行緩存,下次再寫Integer cObj = 100;時(shí),就會(huì)直接從緩存中取,就不會(huì)new了。所以這2個(gè)對(duì)象的引用地址都是指向第一次創(chuàng)建的那個(gè)100的對(duì)象地址。
總結(jié):“==”對(duì)于基本數(shù)據(jù)類型進(jìn)行比較的就是他們的值是否相等,而對(duì)于引用類型進(jìn)行比較的就是對(duì)象在內(nèi)存地址的值,而我們知道Java中對(duì)象的創(chuàng)建是存放在堆中的,而對(duì)象存放的地址是存儲(chǔ)在棧中,所以這個(gè)比較也就是對(duì)比棧中的值是否相等。
“equals”
這個(gè)方法是Object上帝類中的,我們直接去看看它長什么樣子

我們可以看出,這個(gè)和上面講的 “==” 其實(shí)是一個(gè)意思,所以當(dāng)我們沒有對(duì)equals進(jìn)行重寫的時(shí)候,也就是使用的是Object類中的equals方法的時(shí)候,其含義與“==”對(duì)比一樣。
那么問題來了,既然是一樣,為何還要多一個(gè)存在呢???其實(shí)這不是多,因?yàn)槲覀冎绬渭兊摹?=”對(duì)比是不能滿足我們的對(duì)比需求的,所以我們一般都會(huì)對(duì)equals進(jìn)行重寫。
而提到equals,Java規(guī)范中對(duì)其有很多的規(guī)定,但是有一點(diǎn)我們必須注意的是,重寫equals的時(shí)候必須要重寫hashCode方法,給出的理由是 為了維持hashCode的一種約定,相同的對(duì)象必須要有相同的hashCode值,但是我們先分析下hashCode這個(gè)方法的實(shí)際作用我們?cè)賮碇vequals和hashCode之間的關(guān)聯(lián),因?yàn)檫@里要分2種情況,并不是Java規(guī)范中那么硬性規(guī)定他們必須關(guān)聯(lián),看了他的作用之后你也就知道他們什么時(shí)候該一起重寫,什么時(shí)候可以不管hashCode。
那么我們這時(shí)候就得說下什么是hashCode方法的作用了,hashCode方法的作用是獲取哈希碼,也叫做散列碼;實(shí)際上就是一個(gè)int整數(shù),該哈希碼的作用就是確定對(duì)象在哈希表中的索引位置,這里出現(xiàn)的散列表概念我們就不展開了,一會(huì)也說不明白,大家只要知道大概知道Java中的散列表類主要是指集合,比如HashMap、HashTable、HashSet等,而哈希碼只有在這些類中才會(huì)起作用,其他情況下就無用了,下面稍微概括一下哈希碼在散列表中是如何起作用的:
我們都知道,散列表存儲(chǔ)的是鍵值對(duì)(key-value),它的特點(diǎn)是:能根據(jù)“鍵”快速的檢索出對(duì)應(yīng)的“值”。這其中就利用到了哈希碼! 散列表的本質(zhì)是通過數(shù)組實(shí)現(xiàn)的。當(dāng)我們要獲取散列表中的某個(gè)“值”時(shí),實(shí)際上是要獲取數(shù)組中的某個(gè)位置的元素。而數(shù)組的位置,就是通過“鍵”來獲取的;更進(jìn)一步說,數(shù)組的位置,是通過“鍵”對(duì)應(yīng)的哈希碼計(jì)算得到的。這個(gè)如果去詳細(xì)了解集合的時(shí)候會(huì)講到的。
接下來有了上面的理解,那么我們就可以分2部講equals重寫了
第一種 不會(huì)創(chuàng)建“類對(duì)應(yīng)的散列表”
這里所說的“不會(huì)創(chuàng)建類對(duì)應(yīng)的散列表”是說:我們不會(huì)在HashSet, Hashtable, HashMap等等這些本質(zhì)是散列表的數(shù)據(jù)結(jié)構(gòu)中,用到該類。在這種情況下,該類的“hashCode() 和 equals() ”沒有半毛錢關(guān)系的!這種情況下,equals() 用來比較該類的兩個(gè)對(duì)象是否相等。而hashCode() 則根本沒有任何作用,所以,不用重寫hashCode()。
第二種 會(huì)創(chuàng)建“類對(duì)應(yīng)的散列表”
這就跟上面的相反了,類會(huì)用在集合里面,這時(shí)候該類的“hashCode() 和 equals() ”是有關(guān)系的:
? ? ? ? 1)、如果兩個(gè)對(duì)象相等,那么它們的hashCode()值一定相同。
? ? ? ? ? ? ? 這里的相等是指,通過equals()比較兩個(gè)對(duì)象時(shí)返回true。
? ? ? ? 2)、如果兩個(gè)對(duì)象hashCode()相等,它們并不一定相等。
因?yàn)樵谏⒘斜碇校琱ashCode()相等,即兩個(gè)鍵值對(duì)的哈希值相等。然而哈希值相等,并不一定能得出鍵值對(duì)相等。補(bǔ)充說一句:“兩個(gè)不同的鍵值對(duì),哈希值相等”,這就是哈希沖突。
此外,在這種情況下。若要判斷兩個(gè)對(duì)象是否相等,除了要覆蓋equals()之外,也要覆蓋hashCode()函數(shù)。否則,equals()無效。
例如,創(chuàng)建Person類的HashSet集合,必須同時(shí)覆蓋Person類的equals() 和 hashCode()方法。 如果單單只是覆蓋equals()方法。我們會(huì)發(fā)現(xiàn),equals()方法沒有達(dá)到我們想要的效果。
總結(jié):equals方法的使用,默認(rèn)使用Object的equals方法,等價(jià)于使用“==”進(jìn)行對(duì)比,而重寫的話根據(jù)自己的邏輯去判斷是否相等,注意后面涉及到的hashCode,雖然第一種情況下equals與hashCode方法沒有關(guān)聯(lián),但是我們還是盡可能的去一起重寫他們,因?yàn)槟阋矝]法說你寫的這個(gè)類肯定不會(huì)用map去存儲(chǔ)。
寫得不好的地方多多海涵,有錯(cuò)誤的地方歡迎留言區(qū)交流指正!
借鑒文章:https://www.cnblogs.com/skywang12345/p/3324958.html
編程不僅是一門技術(shù)!
編程更加是一門藝術(shù)!