“馬有垂韁之義,犬有濕草之仁欺殿。羊羔跪乳報(bào)母恩寄纵,猿偷仙果自奔。
蛛織羅網(wǎng)護(hù)體脖苏,鼠盜余糧防身程拭。梅鹿見食等成群,無義之人可恨棍潘!”
這幾句是在聽評書時(shí)說書人經(jīng)常說的幾句開場白恃鞋,感覺說的很有道理屋吨,這里把其中蘊(yùn)含的道理分享出來給大家。
前兩句出自李汝珍《鏡花緣》山宾, 這兩句話是兩個典故△⒒眨“馬有垂韁之義”资锰,出自《異苑》,說的是前秦世祖皇帝苻堅(jiān)在與容沖的一次交仗中阶祭,不幸戰(zhàn)敗绷杜,落荒而逃,不料一失足掉在了山洞里濒募,爬又爬不上來鞭盟。在這個千鈞一發(fā)之際,他的坐騎突跪在澗邊瑰剃,將韁繩垂了下來齿诉,苻堅(jiān)抓住韁繩爬上來,才脫了大難晌姚≡辆纾“犬有濕草之仁”,出自晉人干寶《搜神記》挥唠,講的是三國時(shí)期吳國人李信純的事抵恋。這李信純有一只狗,取名黑龍宝磨,頗通人性弧关。有一天,李信純外出會朋友唤锉,不想喝得酩酊大醉世囊,回家路上摔倒在一片草地上便睡了過去。恰在這時(shí)窿祥,一批獵人放火圍獵茸习,眼看大火就要燒到李信純身邊,可他渾然不知壁肋。那狗想拉他号胚,卻拉不動。于是便跳到附近的水溝里把全身弄濕浸遗,然后跑回來猫胁,用身上的水將李信純身邊的草打濕,往返多次跛锌,才使得李信純幸免一死弃秆。
羊羔跪乳報(bào)母恩:這是南宋文天祥在《詠羊》中贊頌小羊羔的詩届惋。小羊羔剛生出來,必須喝母羊的奶才會茁壯成長菠赚。它把前腿跪下來吃奶脑豹,表示感謝母親的哺育之恩。從古至今衡查,中國人最重視孝道瘩欺,所謂孝“天之經(jīng)也,地之義也拌牲,人之行也”俱饿。的確如此,孝不僅是天地的基本精神塌忽,還是動物所具備的品德拍埠。烏鴉反哺、羊羔跪乳土居,講的就是禽畜也具備人的孝道枣购。所以,人不孝敬父母擦耀,天地不容坷虑,禽獸不如!
“蛛織羅網(wǎng)護(hù)體,鼠盜余糧防身”意思是蜘蛛知道用制網(wǎng)來保護(hù)自己的身體埂奈,老鼠偷糧食來防餓迄损。“梅鹿見食等成群账磺,無義之人可恨”芹敌,梅花鹿找到食物之后要等到伙伴來了才會食用,不講信義的人是最可恨的垮抗。
今天我們講一點(diǎn)Java的基礎(chǔ)知識氏捞,關(guān)于equals方法,Hashcode方法和兩個對象比較的內(nèi)容冒版。
1液茎、概述和關(guān)系
我們都知道在定義類時(shí),常常需要重新定義equals方法和Hashcode方法辞嗡,但是我們又經(jīng)常分不清它們都是各自干什么用的捆等,如何定義?以及在比較兩個對象是否相等時(shí)該怎樣使用這兩個方法续室,今天我們就講一講栋烤。
equals方法比較清楚,字面意思就是用來進(jìn)行比較挺狰。Hashcode方法用來計(jì)算當(dāng)前對象的Hash值明郭,這個值直白的講就是用來和其它對象做區(qū)分买窟,理論上每個對象都有一個唯一的Hash值,但實(shí)際上也有重復(fù)的薯定,但是重復(fù)的比較概率比較小而已始绍。我們要對兩個對象進(jìn)行比較,離不開這兩個方法的正確定義话侄,這兩個方法如果理解不透徹亏推,定義不合理,則會導(dǎo)致對象無法進(jìn)行正確的比較满葛。
2、重寫equals方法
我們定義一個類時(shí)如果重寫equals方法罢屈,那么在重寫這個方法時(shí)必須遵循以下幾點(diǎn):(x,y代表兩個不同的對象)
(1)嘀韧、對稱性:如果x.equals(y)返回是“true”,那么y.equals(x)也應(yīng)該返回是“true”缠捌。
(2)锄贷、反射性:x.equals(x)必須返回是“true”。
(3)曼月、類推性:如果x.equals(y)返回是“true”谊却,而且y.equals(z)返回是“true”,那么z.equals(x)也應(yīng)該返回是“true”哑芹。
(4)炎辨、一致性:如果x.equals(y)返回是“true”,只要x和y內(nèi)容一直不變聪姿,不管你重復(fù)x.equals(y)多少次碴萧,返回都是“true”。
(5)末购、任何情況下破喻,x.equals(null),永遠(yuǎn)返回是“false”盟榴;
3曹质、重寫hashcode方法
如果equals方法被重寫,那hashcode方法也需要重寫擎场。
在重寫類的hashcode方法是必須遵循以下幾點(diǎn):
(1)羽德、在Java應(yīng)用的同一次執(zhí)行過程中,同一對象被多次調(diào)用迅办,則他們的hashcode值必然相同玩般。而對于同一個應(yīng)用的兩次不同的調(diào)用,它們的Hashcode值可以相同礼饱,也有可能不同坏为。
(2)究驴、對于兩個對象來說,如果他們的equals方法比較返回true匀伏,那么這兩個對象的hashcode必然相同洒忧。這也解釋了為什么String類中,如果兩個對象的equals方法相同够颠,則他們的hashcode值一定相同熙侍。
(3)、對于兩個對象來說履磨,如果使用equals方法返回為false蛉抓,則他們的hashcode的值有可能相等也可能不等(如果不同會提高性能,因?yàn)樵诩现蓄惻袛鄡蓚€對象是否相等剃诅,如果其hashcode不等就直接不用判斷equals方法了)巷送。
(4)、對于Object對象來說矛辕,不同的Object對象的hashcode是不同的笑跛,它們返回的是對象的地址,equals方法返回的也是對象的地址聊品。所以在自己定義的類中如果要添加到集合對象中飞蹂,最好是重寫hashcode和equals方法,不然會自動繼承自O(shè)bject類中的兩個方法而使用對象地址來判斷翻屈,這樣做并不合理陈哑。在重寫自己定義的類時(shí),通常是在類中的根據(jù)某個值如name.hashcode()來進(jìn)行判斷伸眶。
4芥颈、如何比較兩個對象是否相等
那么如何比較兩個對象呢?能否直接根據(jù)hashcode值判斷兩個對象是否相等嗎赚抡?答案肯定是否定的爬坑,因?yàn)椴煌膶ο罂赡軙上嗤膆ashcode值。但是可以根據(jù)hashcode值判斷兩個對象不等涂臣,如果兩個對象的hashcode值不等盾计,則必定是兩個不同的對象。
(1)赁遗、如果要判斷兩個對象是否真正相等署辉,必須通過equals方法。也就是說對于兩個對象岩四,如果調(diào)用equals方法得到的結(jié)果為true哭尝,則兩個對象的hashcode值必定相等;
(2)剖煌、如果equals方法得到的結(jié)果為false材鹦,則兩個對象的hashcode值不一定不同逝淹;
(3)、如果兩個對象的hashcode值不等桶唐,則equals方法得到的結(jié)果必定為false栅葡;
(4)、如果兩個對象的hashcode值相等尤泽,則equals方法得到的結(jié)果未知欣簇。
(5)、在設(shè)計(jì)一個類的時(shí)候?yàn)槿绻貙懥薳quals方法坯约,必須重寫hashCode方法熊咽。
(6)、以下摘自Effective Java一書:
● 在程序執(zhí)行期間闹丐,只要equals方法的比較操作用到的信息沒有被修改横殴,那么對這同一個對象調(diào)用多次,hashCode方法必須始終如一地返回同一個整數(shù)妇智。
● 如果兩個對象根據(jù)equals方法比較是相等的滥玷,那么調(diào)用兩個對象的hashCode方法必須返回相同的整數(shù)結(jié)果氏身。
● 如果兩個對象根據(jù)equals方法比較是不等的巍棱,則hashCode方法不一定得返回不同的整數(shù)。
(7)蛋欣、Java編程思想一書中也有這樣的描述:
“設(shè)計(jì)hashCode()時(shí)最重要的因素就是:無論何時(shí)航徙,對同一個對象調(diào)用hashCode()都應(yīng)該產(chǎn)生同樣的值。如果在講一個對象用put()添加進(jìn)HashMap時(shí)產(chǎn)生一個hashCode值陷虎,而用get()取出時(shí)卻產(chǎn)生了另一個hashCode值到踏,那么就無法獲取該對象了推溃。所以如果你的hashCode方法依賴于對象中易變的數(shù)據(jù)族展,用戶就要當(dāng)心了,因?yàn)榇藬?shù)據(jù)發(fā)生變化時(shí)访忿,hashCode()方法就會生成一個不同的散列碼”凿掂。因此伴榔,在設(shè)計(jì)hashCode方法和equals方法的時(shí)候,如果對象中的數(shù)據(jù)易變庄萎,則最好在equals方法和hashCode方法中不要依賴于該字段踪少。
5、注意事項(xiàng)
重寫Object類的equals()方法的同時(shí)為什必須覆蓋hashCode()方法糠涛?
因?yàn)閖ava的collection很多都需要hashCode()援奢,例如HashTable。
比如說你往里面存了一個值忍捡,你在取這個值的時(shí)候集漾,java實(shí)際上通過hashCode()來找那個值切黔,因?yàn)檫@樣通常比較快。如果你覆蓋了equals()方法帆竹,意味著原來不相等的兩個對象現(xiàn)在可能變得相等绕娘,但hashCode()的值卻不相等,這樣你使用HashTable就會出現(xiàn)存進(jìn)去的東西找不到的問題栽连。千萬不要忽略這個問題险领,因?yàn)镠ashTable等容器類用的非常多,很可能就在一個你不知道的地方間接地用到了秒紧。java類的一個原則就是:你定義的任何類绢陌,都要考慮覆蓋equals和hashCode方法。否則你的類就不能給其他人或其他地方用熔恢。
6脐湾、示例代碼
class Man {
private String name;
private int age;
public Man(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
//如果是空
if(obj==null ){
return false;
}
//如果是自己
if(this==obj){
return true ;
}
//比較兩個Man的屬性值是否相同
if(obj!=null && obj instanceof Man){
if((((Man)obj).name.equals(this.name)) && (((Man)obj).age == this.age))
return true ;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
7、總結(jié)
equals方法和Hashcode方法在我們實(shí)際工作中有時(shí)是會碰到的叙淌,而且這兩個點(diǎn)也是面試的重點(diǎn)秤掌,希望大家多下些功夫,將它們都能熟練掌握鹰霍。本片文章只是起到一個拋磚引玉的作用闻鉴,后續(xù)還需要大家能夠多多使用,多多總結(jié)茂洒。