日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

你所忽略的,覆盖equals时需要注意的事项《effective java》

發(fā)布時(shí)間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 你所忽略的,覆盖equals时需要注意的事项《effective java》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  我們都知道Object的equals的比較其實(shí)就是==的比較,其實(shí)是內(nèi)存中的存放地址的比較。正常邏輯上:類的每個(gè)實(shí)例本質(zhì)上都是唯一的。

  在工作中我們實(shí)際的業(yè)務(wù)邏輯往往有可能出現(xiàn)一些相對特殊的需求需要對equals方法進(jìn)行重寫,那么重寫equals需要注意哪些規(guī)則或者通用的約定呢?

?

equals方法實(shí)現(xiàn)了等價(jià)關(guān)系(equivalence relation):

  • 自反性(reflexive)。對于任何非null的引用值x,x.equals(x)必須返回true。
  • 對稱性(symmetric)。對于任何非null的引用值x和y,當(dāng)且僅當(dāng)y.equals(x)返回true時(shí),x.equals(y)必須返回true。
  • 傳遞性(transitive)。對于任何非null的引用值x、y和z。如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必須返回true。
  • 一致性(consistent)。對于任何非null的引用值x和y,只要equals的比較操作在對象中所用的信息沒有被修改,多次調(diào)用x.equals(x)就會一致地返回true,或者一致的返回false。
  • 對于任何非null的引用值x,x.equals(null)必須返回false。

第一點(diǎn)自反性不需要多說,基本上不可能會出現(xiàn)違背這條約定的情況當(dāng)自己和自己比較的時(shí)候返回false。

第二點(diǎn)對稱性,這種情況還是有可能會出現(xiàn)的。我們可以假設(shè)一個(gè)場景,這個(gè)場景是我們創(chuàng)建一個(gè)類并且里面只有一個(gè)String屬性字段,這個(gè)類需要實(shí)現(xiàn)的是可以不區(qū)分字符串的大小寫。

pubilc final class IgnoreCaseString {private final String s;public IgnoreCaseString(String s) {if (s == null)throw new NullPointerException();this.s = s;}@Overridepublic boolean equals(Object o) {if (o instanceof IgnoreCaseString)return s.equalsIgnoreCase(((IgnoreCaseString) o).s);if (o instanceof String)return s.equalsIgnoreCase((String) o);return false;}

  ...//更多代碼(重寫equals就需要重寫hashCode) }

在這個(gè)類中,equals方法的意圖非常好,它的企圖是可以與普通的字符串對象進(jìn)行互操作。但是這段代碼無意中觸犯了對稱性這個(gè)約定,從new?IgnoreCaseString(“Po”).equals("po")是為true的,但是反過來“po”.equals(new IgnoreCaseString("Po"))的結(jié)果是false。假如違反了這一情況而沒有去更正,他會破壞已有的集合框架的一些方法,使其變的不在準(zhǔn)確。

IgnoreCaseString ics = new IgnoreCaseString("Po");List<IgnoreCaseString> list = new ArrayList<IgnoreCaseString>();list.add(ics);System.out.println(list.contains("po"));List<String> list1 = new ArrayList<>();list1.add("po");System.out.println(list1.contains(ics));

結(jié)果是,此時(shí)list.contains(s)會返回什么結(jié)果呢?沒人知道,在Sun的當(dāng)前實(shí)現(xiàn)中,它碰巧返回false,但這只是這個(gè)特定實(shí)現(xiàn)得出的結(jié)果而已。在其他的實(shí)現(xiàn)中,它有可能返回true(如上面代碼中的list1.contains(ics)),或者拋出一個(gè)運(yùn)行時(shí)(runtime)異常。一旦違反了equals約定,當(dāng)其他對象面對你的對象時(shí),你完全不知道這些對象的行為會這么樣。

第三點(diǎn)傳遞性,equals約定:如果一個(gè)對象等于第二個(gè)對象,并且第二個(gè)對象又等于第三個(gè)對象,則第一個(gè)對象一定等于第三個(gè)對象。無意識違反這一情況其實(shí)不難想象,考慮子類的情形,子類增加的信息會影響到equals的比較結(jié)果。

public class TwoDCoordinate {private final int x;private final int y;public TwoDCoordinate(int x, int y) {this.x = x;this.y = y;}@Overridepublic boolean equals(Object o) {if (!(o instanceof TwoDCoordinate))return false;TwoDCoordinate p = (TwoDCoordinate)o;return p.x == x && p.y == y;}
  ...//更多代碼
(重寫equals就需要重寫hashCode) }
public class ThreeDCoordinate extends TwoDCoordinate{
  
private final int z;
  
public ThreeDCoordinate(int x, int y, int z) {
    
super(x, y); this.z=z;
  }

  @Override
  
public boolean equals(Object o) {
    
if (!(o instanceof TwoDCoordinate))
      
return false;
    
if (!(o instanceof ThreeDCoordinate))
      
return o.equals(this);
    
return super.equals(o) && this.z == ((ThreeDCoordinate) o).z;
  }
  
  ...//更多代碼
(重寫equals就需要重寫hashCode) } ThreeDCoordinate t1 = new ThreeDCoordinate(1, 2, 3);TwoDCoordinate t2 = new TwoDCoordinate(1, 2);ThreeDCoordinate t3 = new ThreeDCoordinate(1, 2, 4);System.out.println(t1.equals(t2));System.out.println(t2.equals(t1));System.out.println(t2.equals(t3));System.out.println(t1.equals(t3));

結(jié)果是true??true? ?true? ?false,上述代碼已經(jīng)滿足了自反性和對稱性的約定,但是沒有滿足傳遞性,t1.equals(t2)為true,t2.equals(t3)為true,t1.equals(t3)卻為false。

這種情況很多程序員會犯。

?想要避免這種情況,其實(shí)可以用getClass測試代替instanceof測試。如將TwoDCoordinate 的equals 方法改為

public boolean equals(Object o) {if (o == null || o.getClass() != this.getClass())return false;TwoDCoordinate p = (TwoDCoordinate)o;return p.x == x && p.y == y;}

這種替代方式其實(shí)不會太糟糕,但是結(jié)果卻不會太理想,暫時(shí)沒有想到令人滿意的辦法實(shí)現(xiàn)既可以擴(kuò)展又不可實(shí)例化的類,但是可以考慮復(fù)合優(yōu)先于繼承。

第四點(diǎn)一致性,equals約定的第四個(gè)要求是,如果兩個(gè)對象相等,它們就必須始終保持相等,除非它們中有一個(gè)對象(或者兩個(gè)都)被修改了。換句話說,可變對象在不同的時(shí)候可以與不同的對象相等,而不可變對象則不會這樣。當(dāng)你在寫一個(gè)類的時(shí)候,應(yīng)該仔細(xì)考慮她是否應(yīng)該是不可變的。如果認(rèn)為它應(yīng)該是不可變的,就必須保證equals方法滿足這樣的限制條件:相等的對象永遠(yuǎn)相等,不相等的對象永遠(yuǎn)不相等。

?

轉(zhuǎn)載于:https://www.cnblogs.com/saoyou/p/10318517.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的你所忽略的,覆盖equals时需要注意的事项《effective java》的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。