国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

java中的equals+hashCode

2019-11-14 15:14:28
字體:
來源:轉載
供稿:網友

【0】README

0.1)本文轉自 core java volume 1, 旨在理清 equals + hashCode方法;


【1】equals方法

1.1) Object中的 equals 方法用于檢測一個對象是否等于另外一個對象;(在Object類中, 這個方法比較的是內存地址, 判斷的是兩個對象是否具有相同引用)
1.2)看個荔枝:
這里寫圖片描述
Hint)

  • H1)為了防備name 或 hireDay 可能為null的情況: 需要使用 Objects.equals 方法;如果兩個參數都為 null, Objects.equals(a, b) 返回 true; 如果其中一個為null, 則返回 false; 否則,兩個參數都不為null, 則調用 a.equals(b);(注意是Objects not Object)
  • H2)利用這個方法, Employee.equals 方法的最后一條語句要改寫為:
return Objects.equals(name, other.name)         && salary == other.salary         && Objects.equals(hireDay, other.hireDay);

1.3)在子類中定義 equals 方法時, 首先調用超類的 equals; 如果檢測失敗,對象就不可能相等, 如果超類中的域都相等, 就需要比較子類中的實例域;
這里寫圖片描述
1.4)java語言規范要求 equals 具有以下特性:

  • 自反性:非空引用 x,x.equals(x) 應該返回true;
  • 對稱性:非空引用x 和 y, x.equals(y) 返回ture, 那么 y.equals(x) 也應該返回ture;
  • 傳遞性:對于 非空引用x 、y 和 z, x.equals(y) 返回ture, 那么 y.equals(z) 也應該返回ture, 則 x.equals(z) 也應該返回 true;
  • 一致性:如果x 和 y 引用的對象沒有發生變化, 反復調用 x.equals(y) 應該返回同樣的結果;
  • 對于任意非空應用x, x.equals(null) 應該返回false;

1.5)出現的問題+解決方法

  • 當子類和父類對象分別作為equals 的隱式參數,導致不滿足對稱性的情況: e.equals(m), 這里的e是一個 Employee對象,m是一個 Manager對象,并且兩個對象具有相同的屬性值;如果在 Employee.equals中用 instanceof 檢測,就會返回 true, 然而這意味著反過來調用:
    m.equals(e) 也需要返回true; 對稱性不允許這個方法調用返回 false, 或者拋出異常;猛然間,讓人感覺到 instanceof 并不是那么完美;
  • 下面從兩個截然不同的情況看一下這個問題:
    • 1)如果子類能夠擁有自己的相等概念, 則對稱性需要將強制采用getClass 進行檢測;
    • 2)如果由超類決定相等的概念, 那么就可以使用 instanceof 進行檢測, 這樣可以在不同子類的對象間進行相等的比較;

【2】下面給出編寫一個完美的 equals 方法的建議:

  • 2.1)顯式參數命名為 otherObject, 稍后需要將它轉換為另一個叫做 other的變量;
  • 2.2)檢測this 與 otherObject 是否引用同一個對象:
    if(this == otherObject) return true; 實際上, 這是一種經常采用的形式, 因為計算這個等式要比一個一個地比較類中的域所付出的代價小得多;
  • 2.3)檢測otherObject 是否為 null, 如果為 null ,則返回 false, 這項檢測很有必要:
    if(otherObject == null) return false;
  • 2.4)比較this 與 otherObject 是否屬于同一個類: 如果equals 的語義在每個子類中有所改變,就是用 getClass 進行檢測:if(getClass() != otherObject.getClass()) return false;
  • 2.5) 將 otherObject 轉換為 相應的類類型變量:
    ClassName other = (ClassName)otherObject;
  • 2.6)現在開始對所有需要比較的域進行比較了:
    使用 == 比較基本類型域, 使用 equals比較對象域, 如果所有的域都匹配返回 true, 否則返回 false;
    return field1 == other.field1 && Objects.equals(field2, other.field2) && ......;
    如果在子類中重新定義 equals, 就要在其中包含 調用 super.equals(other);

Hint)對于數組類型的域, 可以使用靜態的Arrays.equals 方法檢測相應的 數組元素是否相等;
Alert)看個荔枝(下面是實現 equals 方法的一種常見的錯誤):
這里寫圖片描述
代碼分析(Analysis):

  • A1)這個方法聲明的顯式參數類型是 Employee, 其結果并沒有 覆蓋 Object類的 equals 方法,而是定義了一個完全無關的方法;
  • A2)為了避免發生類型錯誤, 可以使用 @Override 對覆蓋超類的方法進行標記;

    @Overridepublic boolean equals(Object other)
  • A3)如果出現了錯誤,并且正在定義一個新方法,編譯器就會給出 錯誤報告;如, 假設將下面的聲明添加到 Employee類中, 就會看到一個錯誤報告, 這是因為這個方法并沒有覆蓋超類Object 中的 任何方法:

    @Override public boolean equals(Employee other)

    【3】hashCode 方法

    3.1)定義:散列碼是由對象導出的一個整型值, 散列碼沒有規律的;如,x和y 是兩個不同的對象, x.hashCode() 和 y.hashCode() 基本上不會相同的;
    3.2)String 類的 hashCode 散列碼:

  • 3.2.1)String類通過下列算法計算散列碼:

    int hash = 0;for(int i=0;i<length(); i++)hash = 31 * hash + charAt(i);
  • 3.2.2) hashCode方法定義在了 Object類, 因此每個對象都有一個默認的散列碼, 其值為對象的存儲地址:
    這里寫圖片描述
    對以上打印結果的分析(Analysis):

    • A1)字符串s 和 t 擁有相同的散列碼, 這是因為字符串的散列碼是由內容導出的, 而字符串緩沖sb 和 tb 卻有著不同的散列碼,這是因為 在StringBuffer 類中沒有定義hashCode 方法,它的散列碼是有 Object類的默認 hashCode 方法,以便用戶可以 將對象插入到散列表中;
    • A2) hashCode方法應該返回一個整型數值,并合理的組合實例域的散列碼, 以便能夠讓各個不同的對象產生的散列碼更加均勻;

3.3)看個荔枝, 下面是 Employee類 的 hashCode方法:
這里寫圖片描述
3.4)還可以在java7中做兩個改進(imPRovement):

  • I1) 最好使用 null 安全 的方法 Objects.hashCode , 如果參數為null, 這個方法會返回0, 否則返回對參數調用 hashCode的結果;
  • I2)還有一個方法: 需要組合多個散列值, 可以調用 Objects.hash 并提供多個參數,這個方法會對各個參數調用 Objects.hashCode, 并組合這些散列值; 如 Employee.hashCode 的方法可以簡寫為:

    public int hashCode(){return Objects.hash(name, salary, hireDay);}

    Attention)

  • A1) equals 方法與 hashCode 的定義必須一致, 如果x.equals(y) 返回 true, 那么 x.hashCode() 就必須與 y.hashCode() 具有相同的值;
  • A2) 如, 如果用定義的Employee.equals 比較雇員的Id, 那么 hashCode就需要散列Id, 而不是 雇員的 姓名或存儲地址;

Hint)如果存在數組類型的域, 那么可以使用靜態的 Arrays.hashCode 方法計算一個散列碼, 這個散列碼由數組元素的散列碼組成;


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 丹江口市| 松阳县| 关岭| 铅山县| 淮滨县| 茂名市| 乐陵市| 广宁县| 陈巴尔虎旗| 乌拉特前旗| 报价| 望城县| 德兴市| 内黄县| 河曲县| 佛山市| 大冶市| 龙江县| 芒康县| 绥中县| 梓潼县| 永嘉县| 仁化县| 陈巴尔虎旗| 北海市| 江山市| 西藏| 尚义县| 台南市| 拉萨市| 呼图壁县| 安龙县| 巴南区| 兰考县| 江阴市| 阿克陶县| 长汀县| 雅江县| 灵武市| 三河市| 洪雅县|