目錄
一、概述​​
四、hashCode 方法
五、小结
首頁 Java java教程 詳解Java中的 ==, equals 與 hashCode的區別與聯繫的範例程式碼

詳解Java中的 ==, equals 與 hashCode的區別與聯繫的範例程式碼

Mar 14, 2017 am 11:25 AM


一、概述​​

1、概念

  • #== :運算符產生的是一個boolean結果,它計算的是運算元的值之間的關係

  • # equals  : Object實例方法,比較兩個物件content


  • #是否相同

    hashCode : Object 的

    native方法

    , 取得對象的

    雜湊值

    ,用於確定該物件在雜湊表中的

    索引位置,它實際上是int型別整數二、關係運算子==1、運算元的值


基本
    資料型別
  • 變數
    在Java中有八種基本資料型別:  浮點型

    float
  • (4 byte), double(8 byte)

  整數型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)


  • 字元型: char(2 byte)  布林型: boolean(JVM規範沒有明確規定其所佔的空間大小,僅規定其只能夠取字面值”true”和”false”)   對於這八種基本資料類型的變量,變數直接儲存的是「值」。因此,在使用關係運算子 == 來進行比較時,比較的就是「值」本身。 要注意的是,浮點型和整數型都是有符號類型的(最高位元只用來表示正負,不參與計算【以byte 為例,其範圍為-2^7 ~ 2^7 - 1,-0即-128】),而char是無符號類型的(所有位元均參與計算,所以char類型取值範圍為0~2^16-1)





引用

類型變數
在Java中,


引用類型的變數儲存的並不是「值」本身,而是與其關聯的物件在記憶體中的位址。例如下面這行程式碼,

    String str1;
登入後複製
  這句話宣告了一個引用型別的變量,此時它並沒有和任何物件關聯。

  而透過

new 來產生一個對象,並將這個物件和str1進行綁定:

str1= new String("hello");
登入後複製

  那麼str1 就指向了這個對象,此時

引用變數str1中儲存的是它指向的物件在記憶體中的儲存位址,並不是「值」本身,也就是說並不是直接儲存的字串」hello」

。這裡面的引用和 C/C++ 中的指標很類似。 #########2、小結###### 因此,對於關係運算子==:############若運算元的型別是##### #基本資料型別######,則該關係運算子判斷的是左右兩邊運算元的#######值######是否相等########### #若運算元的型別是######引用資料型別######,則該關係運算子判斷的是左右兩邊運算元的######記憶體位址#######是否相同。 ######也就是說,若此時傳回true,則該運算元作用的一定是同一個物件。 #####################三、equals方法######1、來源###  equals方法是基底類別Object中的實例方法,因此對所有###繼承###於Object的類別都會有該方法。 ###   ###  在Object 中的宣告:###
    public boolean equals(Object obj) {}
登入後複製
######2、equals方法的作用### ###初衷:### ###判斷兩個物件的### content ###是否相同######### 為了更直覺地理解equals方法的作用,我們先看###Object類別###中equals方法的實作。 ###
  public boolean equals(Object obj) {    return (this == obj);
  }
登入後複製
###  很顯然,###在Object類別中,equals方法是用來比較兩個物件的參考是否相等,也就是是否指向同一個物件。 ######

  但我们都知道,下面代码输出为 true:

public class Main {
    public static void main(String[] args) {
        String str1 = new String("hello");
        String str2 = new String("hello");

        System.out.println(str1.equals(str2));
    }
}
登入後複製

原来是 String 类重写了 equals 方法:

public boolean equals(Object anObject) {   // 方法签名与 Object类 中的一致
    if (this == anObject) {     // 先判断引用是否相同(是否为同一对象),
        return true;
    }    if (anObject instanceof String) {   // 再判断类型是否一致,
        // 最后判断内容是否一致.
        String anotherString = (String)anObject;        
        int n = count;        
        if (n == anotherString.count) {        
        char v1[] = value;        
        char v2[] = anotherString.value;        
        int i = offset;        
        int j = anotherString.offset;       
         while (n-- != 0) {            
         if (v1[i++] != v2[j++])            
         return false;
        }        return true;
        }
    }    return false;
}
登入後複製

即对于诸如“字符串比较时用的什么方法,内部实现如何?”之类问题的回答即为:

使用equals方法,内部实现分为三个步骤:

  • 比较引用是否相同(是否为同一对象),

  • 判断类型是否一致(是否为同一类型),

  • 最后 比较内容是否一致

Java 中所有内置的类的 equals 方法的实现步骤均是如此,特别是诸如 Integer,Double 等包装器类。


3、equals 重写原则

对象内容的比较才是设计equals()的真正目的,Java语言对equals()的要求如下,这些要求是重写该方法时必须遵循的:

  • 对称性: 如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true” ;

  • 自反性: x.equals(x)必须返回是“true” ;

  • 类推性: 如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true” ;

  • 一致性: 如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true” ;

  • 对称性: 如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

  • 任何情况下,x.equals(null)【应使用关系比较符 ==】,永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”


4、小结
 因此,对于 equals 方法:

  • 本意比较两个对象的 content 是否相同

  • 必要的时候,我们需要重写该方法,避免违背本意,且要遵循上述原则


四、hashCode 方法

1、hashCode 的来源
  hashCode 方法是基类Object中的 实例native方法,因此对所有继承于Object的类都会有该方法。
  
  在 Object类 中的声明(native方法暗示这些方法是有实现体的,但并不提供实现体,因为其实现体是由非java语言在外面实现的):

     public native int hashCode();
登入後複製

2、哈希相关概念
 我们首先来了解一下哈希表:

  • 概念 : Hash 就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出(int),该输出就是散列值。这种转换是一种 压缩映射,也就是说,散列值的空间通常远小于输入的空间。不同的输入可能会散列成相同的输出,从而不可能从散列值来唯一的确定输入值。简单的说,就是一种将任意长度的消息压缩到某一固定长度的消息摘要函数

  • 应用–数据结构 : 数组的特点是:寻址容易,插入和删除困难; 而链表的特点是:寻址困难,插入和删除容易。那么我们能不能综合两者的特性,做出一种寻址容易,插入和删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表,哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法——拉链法,我们可以理解为 “链表的数组”,如图:

             詳解Java中的 ==, equals 與 hashCode的區別與聯繫的範例程式碼
                            图1 哈希表示例

     左邊很明顯是個數組,數組的每個成員都是一個鍊錶。此資料結構所容納的所有元素均包含一個指針,用於元素間的連結。我們根據元素的自身特徵把元素分配到不同的鍊錶中去,也是根據這些特徵,找到正確的鍊錶,再從鍊錶中找出這個元素。 其中,將根據元素特徵計算元素數組下標的方法就是雜湊法。

  • 拉鍊法的適用範圍 : 快速查找,刪除的基本資料結構,通常需要總資料量可以放入記憶體。

  • 重點:  
    hash函數選擇,針對字串,整數,排列,具體對應的hash方法;
    碰撞處理,一種是open hashing,也稱為拉鍊法,另一種是closed hashing,也稱為開地址法,opened addressing。


3、hashCode 簡述
 在 Java 中,由 Object 類別定義的 hashCode 方法會針對不同的物件傳回不同的整數。 (這是透過將該物件的內部位址轉換成一個整數來實現的,但是 JavaTM 程式語言不需要這種實作技巧)。

 hashCode 的常規協定是:

  • 在Java 應用程式執行期間​​,在對相同物件多次調用hashCode 方法時,必須一致地傳回相同的整數,前提是將物件進行equals 比較時所使用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。

  • 如果根據 equals(Object) 方法,兩個物件是相等的,那麼對這兩個物件中的每個物件呼叫 hashCode 方法都必須產生相同的整數結果。

  • 如果根據equals(java.lang.Object) 方法,兩個物件不相等,那麼對這兩個物件中的任一物件上呼叫hashCode方法 不要求一定會產生不同的整數結果。但是,程式設計師應該意識到,為不相等的物件產生不同整數結果可以提高雜湊表的效能。
     
      要想進一步了解hashCode 的作用,我們必須先要了解Java中的容器,因為HashCode 只是在需要用到哈希演算法的資料結構中才有用,例如HashSet, HashMap 和Hashtable

      Java中的集合(Collection)有三類,一類是List,一類是Queue,再有一類就是Set。 前兩個集合內的元素是有序的,元素可以重複;最後一個集合內的元素無序,但元素不可重複。

      那麼, 這裡就有一個比較嚴重的問題:要想保證元素不重複,可兩個元素是否重複應該依據什麼來判斷呢? 這就是 Object.equals 方法了。但是,如果每增加一個元素就檢查一次,那麼當元素很多時,後面加入集合中的元素比較的次數就非常多了。 也就是說,如果集合中現在已經有1000個元素,那麼第1001個元素加入集合時,它就要呼叫1000次equals方法。這顯然會大大降低效率。於是,Java採用了哈希表的原理。 這樣,我們對每個要存入集合的元素使用雜湊演算法算出一個值,然後根據該值計算出元素應該在數組的位置。所以,當集合要加入新的元素時,可分為兩個步驟:
         

  • 先呼叫這個元素的hashCode 方法,然後根據所所得的值計算出元素應該在數組的位置。如果這個位置上沒有元素,那麼直接將它儲存在這個位置上;

  • #如果這個位置上已經有元素了,那麼呼叫它的equals方法與新元素進行比較:相同的話就不存了,否則,將其存在這個位置對應的鍊錶中(Java 中HashSet, HashMap 和Hashtable的實作總會元素放到鍊錶的錶頭) 。


4、equals 與hashCode

 前提: 談到hashCode就不得不說equals方法,二者均是Object類別裡的方法。由於Object類別是所有類別的基類,所以在所有類別中都可以重寫這兩個方法。

  • 原則1 : 如果x.equals(y) 回傳“true”,那麼x 和y 的hashCode() 必須相等;

  • #原則2 : 如果x.equals(y) 回傳“false”,那麼x 和y 的hashCode() 有可能相等,也有可能不等;

  • 原则 3 : 如果 x 和 y 的 hashCode() 不相等,那么 x.equals(y) 一定返回 “false” ;

  • 原则 4 : 一般来讲,equals 这个方法是给用户调用的,而 hashcode 方法一般用户不会去调用 ;

  • 原则 5 : 当一个对象类型作为集合对象的元素时,那么这个对象应该拥有自己的equals()和hashCode()设计,而且要遵守前面所说的几个原则。


5、实现例证

 hashCode()在object类中定义如下:

public native int hashCode();
登入後複製

 说明是一个本地方法,它的实现是根据本地机器相关的。

 String 类是这样重写它的:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence{
    /** The value is used for character storage. */
    private final char value[];     //成员变量1

    /** The offset is the first index of the storage that is used. */
    private final int offset;      //成员变量2

    /** The count is the number of characters in the String. */
    private final int count;       //成员变量3

   /** Cache the hash code for the string */
    private int hash; // Default to 0    //非成员变量

    public int hashCode() {    int h = hash;        int len = count;         //用到成员变量3
    if (h == 0 && len > 0) {        int off = offset;         //用到成员变量2
        char val[] = value;       //用到成员变量1
            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];       //递推公式
            }
            hash = h;
        }        return h;
    }
}
登入後複製

对程序的解释:h =  s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],由此可以看出,对象的hash地址不一定是实际的内存地址。


五、小结

  • hashcode是系统用来快速检索对象而使用

  • equals方法本意是用来判断引用的对象是否一致

  • 重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性


以上是詳解Java中的 ==, equals 與 hashCode的區別與聯繫的範例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP與Python:用例和應用程序 PHP與Python:用例和應用程序 Apr 17, 2025 am 12:23 AM

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。

See all articles