Java---hashCode()和equals()

来源:https://www.cnblogs.com/zhuweiheng/archive/2018/01/07/8228886.html
-Advertisement-
Play Games

1.hashCode()和equals() API hashCode()和equals()都來自上帝類Object, 所有的類都會擁有這兩個方法,特定時,覆寫它們。 它們是用來在同一類中做比較用的,尤其是在容器里如Set存放同一類對象時用來判斷放入的對象是否重覆。 下麵是API中的介紹: boole ...


1.hashCode()和equals() API

hashCode()和equals()都來自上帝類Object, 所有的類都會擁有這兩個方法,特定時,覆寫它們。

它們是用來在同一類中做比較用的,尤其是在容器里如Set存放同一類對象時用來判斷放入的對象是否重覆。

下麵是API中的介紹:

boolean equals (Object obj) :比較兩個對象是否相等。                                                                                                

equals方法在非空對象引用上實現等價關係:

自反性 :對於任何非空的參考值x , x.equals(x)應該返回true 。
對稱性 :對於任何非空引用值x和y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true。
傳遞性 :對於任何非空引用值x,y 和 z,如果 x.equals(y) 返回 true並且 y.equals(z)返回true,那麼 x.equals(z) 應返回true。
一致性 :對於任何非空引用值x 和 y ,多次調用x.equals(y)始終返回true或始終返回false ,前提是對象上 equals 比較中所用的信息沒有被修改。

對於任何非空引用值 x,x.equals(null) 都應返回 false。

Object 類的 equals 方法實現對象上差別可能性最大的相等關係;即,對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true(x == y 具有值 true)。

註意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。

int hashCode () :返回對象的哈希碼值。                                                                                                                           

支持此方法是為了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

hashCode 的常規協定是:

在 Java 應用程式執行期間,在對同一對象多次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。

從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。
如果根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用 hashCode 方法都必鬚生成相同的整數結果。
如果根據
equals(java.lang.Object) 方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不要求一定生成不同的整數結果。但是,程式員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。

實際上,由 Object 類定義的 hashCode 方法確實會針對不同的對象返回不同的整數。(這一般是通過將該對象的內部地址轉換成一個整數來實現的,但是 JavaTM 編程語言不需要這種實現技巧。)

要點:

(1)equals()相等的兩個對象,hashcode()一定相等,equals()不相等的兩個對象,卻並不能證明它們的hashcode()不相等;

    equals()方法不相等的兩個對象,hashCode()有可能相等。

(2)hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

(3)在object類中,hashcode()方法是本地方法,返回的是本對象(單一對象)的地址值;而object類中的equals()方法比較的 

    也是兩個對象的地址值。如果equals()相等,說明兩個對象地址值也相等,hashcode()也就相等。

(4)當我們重寫一個對象的equals方法,通常有必要重寫它的hashCode方法。以維護 hashCode 方法的常規協定 


equals()與==的比較

(1)'=='是用來比較兩個變數(基本類型和對象類型)的值是否相等的。 如果兩個變數是基本類型的,直接比較值就可以了。如果兩個變數是對象類型的,比較的是這兩個對象在棧中的引用(即地址)。

對象是放在堆中的,棧中存放的是對象的引用(地址)。由此可見'=='是比較棧中的值。如果要比較堆中對象的內容是否相同,那麼就要重寫equals方法了
(2)Object類中的equals方法就是用'=='來比較的,所以如果沒有重寫equals方法,equals和==是等價的。

通常我們會重寫equals方法,讓equals比較兩個對象的屬性內容,而不是比較對象的引用(地址),因為往往我們覺得比較對象的內容是否相同比比較對象的引用(地址)更有意義。


2.HashCode的作用

數據結構---哈希表中簡單介紹了散列表的原理,一句話就是:hash演算法提高了查找元素的效率。

如何查找一個集合中是否包含有某個對象呢?

一種方法是逐一取出每個元素與要查找的對象,使用equals方法比較的是否相等。如果一個集合中有很多個元素,則效率很慢。

哈希演算法的思想:HashCode應該就和使用拼音查詢漢字相似(建立拼音索引),這種方式將集合分成若幹個存儲區域,每個對象可以計算出一個哈希碼,可以將HashCode分組,每組分別對應某個存儲區域,根據一個對象的HashCode就可以確定該對象應該存儲在哪個區域。

Object類中定義了一個hashCode()方法來返回每個Java對象的HashCode,當從Set集合中查找某個對象時,Java系統首先調用對象的hashCode()方法獲得該對象的hashCode表,然後根據hashCode找到相應的存儲區域,最後取得該存儲區域內的每個元素與該對象進行equals方法比較。這樣就不用遍歷所有對象,提高效率。

image

HashCode在Java容器中的應用

對於List集合、數組而言,HashCode不重要,但是對於HashMap、HashSet、HashTable等而言,它變得異常重要。所以在使用HashMap、HashSet、HashTable時一定要註意hashCode。對於一個對象而言,其hashCode過程就是一個簡單的Hash演算法的實現,其實現過程對你實現對象的存取過程起到非常重要的作用。

一個對象肯定存在若幹個屬性,如何選擇屬性實現均勻散列(哈希表也稱為散列表,其要保持儘可能均勻,不重覆),考驗著一個人的設計能力。

如果我們將所有屬性進行散列,這必定會是一個糟糕的設計,因為對象的hashCode方法無時無刻不是在被調用,如果太多的屬性參與散列,那麼需要的操作數時間將會大大增加,這將嚴重影響程式的性能。

如果較少屬相參與散列,散列的多樣性會削弱,會產生大量的散列“衝突或碰撞”,除了不能夠很好的利用空間外,在某種程度也會影響對象的查詢效率。其實這兩者是一個矛盾體,散列的多樣性會帶來性能的降低。

3.覆寫(@Override)hashCode()和equals() 的慄子

public class Employee implements Comparable<Employee> {

    private String name;
    private int age;
    
    
    public Employee() {
        super();
        
    }
    
    public Employee(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Emplooye [name=" + name + ", age=" + age + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public int compareTo(Employee o) {
        
        int temp = this.age - o.age;
        return temp==0? this.name.compareTo(o.name):temp;
    }
    
}

2

2018-01-07


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安全性 a、 編寫線程安全的代碼,其核心在於要對狀態的訪問、更改等操作進行管理,特別是對共用的、可變的狀態的訪問。java中主要的同步機制有synchronized(獨占鎖)、volatile類型的變數、顯式鎖、原子變數。 b、修複同步問題的方式: 1、不線上程之間共用該狀態變數 2、將狀態變數修改 ...
  • 1、什麼是python 引用官方的話:Python是一種易於學習,強大的編程語言。它具有高效的高級數據結構,並通過簡單而有效的方法來進行面向對象編程。Python的優雅語法和動態類型,以及其解釋性質,使其成為在大多數平臺上的許多領域的腳本和快速應用程式開發的理想語言。 這段話怎麼理解呢?我們知道,任 ...
  • JVM的記憶體分區 這篇文章嘗試討論清楚JVM的記憶體分區情況。 1. JVM的記憶體和系統記憶體的關係 下圖是對系統記憶體及JVM記憶體的大致描繪 對大多數操作系統,記憶體可以分為物理記憶體RAM及Swap(交換區)兩大部分,Swap Space在物理上是一塊獨立的磁碟區域,當操作系統發現記憶體不夠使用時,便開始使 ...
  • 介面: 暫時可以理解為是一種特殊的抽象類 介面是功能的集合,可以看作是一種數據類型,是比抽象類更抽象的“類” 介面只描述所應該具備的方法,並沒有具體實現,具體實現由介面的實現類(相當於介面的子類)來完成 這樣將功能的實現與定義分離,優化了程式設計 介面的成員方法全抽象,不能存在帶有方法體的方法 介面 ...
  • 1,關於Spring MVC的核心控制器DispatcherServlet的作用,以下說法錯誤的是( ) A,它負責接收HTTP請求 B,載入配置文件 C,實現業務操作 D,初始化上下應用對象ApplicationContext 正確答案:C SpringMVC是Spring中的模塊,它實現了mvc ...
  • 準備工作: 在web.xml中配置shiro核心過濾器 在spring配置文件中提供核心過濾器運行所需要的輔助bean對象,在對象內註入安全管理器 攔截認證 配置三個url 攔截除了登錄頁面以及認證action之外所有請求 編寫shiro認證 編寫自己login的action 編寫自定義realm ...
  • http://blog.csdn.net/chgaowei/article/details/6427731 為了支持c++的多態性,才用了動態綁定和靜態綁定。理解他們的區別有助於更好的理解多態性,以及在編程的過程中避免犯錯誤。 需要理解四個名詞: 1、對象的靜態類型:對象在聲明時採用的類型。是在編譯 ...
  • Java提供了大量持有對象的方式: (1) 數組將數字與對象聯繫起來。 它保存類型明確的對象,查詢對象時,不需要對結果做類型轉換。它可以是多維的, 可以保存基本類型的數據。 但是,數組一旦生成,其容量就不能改變。 (2)Collection保存單一的元素,而Map保存相關聯的鍵值對。有了Java的泛 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...