開(kāi)心一笑
【一對(duì)夫婦避孕失敗后生了一個(gè)小男孩,孩子一生出來(lái)就緊握拳頭酵镜,一直笑個(gè)不停.護(hù)士把他的拳頭一掰開(kāi).發(fā)現(xiàn)里面有一把避孕藥碉碉,接著小男孩開(kāi)口說(shuō)話了:“你們兩個(gè)想弄死我,沒(méi)那么容易淮韭,哈哈哈】
提出問(wèn)題
項(xiàng)目開(kāi)發(fā)中垢粮,對(duì)象都通用的方法要注意那些???
解決問(wèn)題
覆蓋equals時(shí)請(qǐng)遵守通用約定
先溫習(xí)下枯燥的理論知識(shí),很無(wú)聊缸濒,但很重要足丢。
- 自反性:對(duì)于任何非null的引用值x,x.equals(x)必須返回true.
- 對(duì)稱性:對(duì)于非空的引用值x,y庇配,當(dāng)且僅當(dāng)x.equals(y)返回true時(shí)斩跌,y.equals(x)必須返回true.
- 傳遞性:對(duì)于任何非null的引用值x,y,z,如果x.equals(y)=true捞慌,y.equals(z)=true耀鸦,那么x.equals(z)也必須返回true。
- 一致性:對(duì)于任何非null的引用值x,y啸澡,只要equals的比較操作在對(duì)象中所用的信息沒(méi)有被修改袖订,多次調(diào)用x.equals(y)就會(huì)一致地返回true,或一致地返回false.
- 對(duì)于非null的引用值x嗅虏,x.equals(null)必須返回false.
高質(zhì)量equals方法的訣竅
- 使用==操作符檢查參數(shù)是否為這個(gè)對(duì)象的引用洛姑。
- 使用instanceof操作符檢查參數(shù)是否為正確的類型。
- 把參數(shù)轉(zhuǎn)換成正確的類型皮服。
- 當(dāng)編寫(xiě)完成了equals方法之后楞艾,應(yīng)該問(wèn)自己三個(gè)問(wèn)題参咙,它是否是對(duì)稱的、傳遞的硫眯、一致的蕴侧。
我用開(kāi)發(fā)工具自動(dòng)幫我生成equals方法:
@Override
public boolean equals(Object o) {
//使用==操作符檢查參數(shù)是否為這個(gè)對(duì)象的引用
if (this == o) return true;
//使用instanceof操作符檢查參數(shù)是否為正確的類型
if (!(o instanceof AyTest)) return false;
//把參數(shù)轉(zhuǎn)換成正確的類型
AyTest ayTest = (AyTest) o;
if (flowerNum != ayTest.flowerNum) return false;
return true;
}
覆蓋equals時(shí)總要覆蓋hashCode
覆蓋equals方法,必須覆蓋hashCode方法两入。如果不這樣做净宵,就會(huì)違反Object.hashCode的通用約定,從而也導(dǎo)致該類無(wú)法結(jié)合所有基于散列的結(jié)合一塊正常運(yùn)轉(zhuǎn)裹纳,這樣的結(jié)合包括HashMap择葡、HashSet和Hashtable
//這里引用課本的例子,非原創(chuàng)
public final class PhoneNumber {
private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 999, "prefix");
rangeCheck(lineNumber, 9999, "line number");
this.areaCode = (short)areaCode;
this.prefix = (short)prefix;
this.lineNumber = (short)lineNumber;
}
private static void rangeCheck(int arg, int max, String name) {
if (arg < 0 || arg > max) {
throw new IllegalArgumentException(name + ": " + arg);
}
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof PhoneNumber)) {
return false;
}
PhoneNumber pNumber = (PhoneNumber)o;
return (pNumber.lineNumber == lineNumber) && (pNumber.prefix == prefix) && (pNumber.areaCode == areaCode);
}
}
測(cè)試?yán)樱?/p>
public static void hashCodePhoneNumber() {
Map<PhoneNumber, String> map = new HashMap<PhoneNumber, String>();
PhoneNumber phoneNumber = new PhoneNumber(707, 867, 9876);
map.put(phoneNumber, "Jenny");
//這里是重點(diǎn) 重點(diǎn) 重點(diǎn) 一個(gè)是new 出來(lái)的 一個(gè)是 原來(lái)的phoneNumber
System.out.println(map.get(new PhoneNumber(707, 867, 9876)));
System.out.println(map.get(phoneNumber));
}
執(zhí)行結(jié)果:
null
Jenny
解釋一下:
不去覆蓋hashCode剃氧,使用map.put時(shí)刁岸,我們是把這些PhoneNumber對(duì)象放在各個(gè)不同的盒子里,而我們?nèi)ap.get()的時(shí)候她我,只是去某一個(gè)盒子里去找,而如果我們覆蓋了hashCode方法迫横,這時(shí)番舆,如果通過(guò)hashCode計(jì)算出來(lái)的值是相等的,就會(huì)放在同一個(gè)盒子里矾踱。這樣恨狈,只要我們對(duì)象中保存的值是完全一致的,就會(huì)找到這個(gè)key所對(duì)應(yīng)的value呛讲。
始終要覆蓋toString
如果我們不覆蓋類的toString()方法禾怠,后果可能是當(dāng)我們需要去打印這個(gè)類的對(duì)象時(shí),會(huì)有一些并非是我們想要的那種結(jié)果”锤椋現(xiàn)在開(kāi)發(fā)工具很方便吗氏,可以使用開(kāi)發(fā)工具自動(dòng)幫助我們生成。
謹(jǐn)慎的覆蓋clone
拷貝的含義是:
- x.clone() != x
- x.clone().getClass() == x.getClass()
- x.clone().equals(x)
覆蓋clone方法要非常小心雷逆,如果類里面含有復(fù)雜數(shù)據(jù)類型弦讽,要進(jìn)行深度復(fù)制,如果類里面有final屬性膀哲,則無(wú)法進(jìn)行clone往产,因?yàn)閒inal屬性在clone時(shí)無(wú)法再進(jìn)行賦值。
最好呢就是別去覆蓋這個(gè)方法某宪,需要復(fù)制的話可以使用拷貝構(gòu)造器和靜態(tài)拷貝工廠
考慮實(shí)現(xiàn)Comparable接口
comparaTo方法不是Object中的方法仿村,而是Comparable接口中唯一的方法。該方法不僅可進(jìn)行等同性比較兴喂,還可以進(jìn)行順序比較蔼囊。
接口的通用約定是按照equals方法來(lái)定義的焚志,但有序集合使用了compareTo方法的等同性測(cè)試。
如果是是一個(gè)值類压真,而且具有明顯的內(nèi)在排序關(guān)系娩嚼,就因該堅(jiān)決實(shí)現(xiàn)該接口。
如果你正在編寫(xiě)一個(gè)值類滴肿,它具有非常明顯的內(nèi)在排序關(guān)系岳悟,比如按字母順序、按數(shù)值順序或者按照年代順序泼差,那就應(yīng)該堅(jiān)決考慮實(shí)現(xiàn)這個(gè)接口贵少。
參考文章
【1】Effective Java:對(duì)于所有對(duì)象都通用的方法
【2】Java中equals和==的區(qū)別
【3】Effective Java——對(duì)所有對(duì)象通用的方法
【4】Effective Java 讀書(shū)筆記之二 對(duì)于所有對(duì)象都通用的方法
【5】考慮實(shí)現(xiàn)Comparable接口
讀書(shū)感悟
來(lái)自韓寒《我所理解的生活》
- 我所理解的生活就是做著自己喜歡的事情,養(yǎng)活自己堆缘,養(yǎng)活家人滔灶。生活不是攀爬高山,也不是深潛海溝吼肥,它只是在一張標(biāo)配的床上睡出你的身形录平。我所理解的生活就是和自己喜歡的一切在一起。
- 緣分不是走在街上非要撞見(jiàn)缀皱,緣分就是睡前醒后彼此想念斗这。
- 打死也不能放棄,窮死也不能?chē)@氣啤斗,要讓笑話你的人成為笑話表箭。
- 可以后悔,但不留遺憾钮莲,有很多事情做了以后發(fā)現(xiàn)自己傻了或者失敗了免钻,但還是要去做。
- 世間萬(wàn)千種寵愛(ài)崔拥,無(wú)數(shù)種人心极舔,得之我幸,不得我也沒(méi)什么不幸握童。
- 我相信真誠(chéng)相待姆怪,也相信倒霉認(rèn)栽。
- 每個(gè)人的道路都不同澡绩,我走在我的野路上稽揭,她走在她的大路上,都值得祝福肥卡。只要不走歪路邪路溪掀,每條道路都有成功的方式。
其他
如果有帶給你一絲絲小快樂(lè)步鉴,就讓快樂(lè)繼續(xù)傳遞下去揪胃,歡迎轉(zhuǎn)載璃哟,點(diǎn)贊,頂喊递,歡迎留下寶貴的意見(jiàn)随闪,多謝支持!