欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文讀懂 Java 中的 ==、equals () 與 hashCode ()原理與避坑指南

 更新時(shí)間:2025年09月05日 10:49:28   作者:凜冬君主  
在 Java 開發(fā)中,==、equals()?和?hashCode()?是處理對(duì)象比較和哈希計(jì)算的核心元素,理解它們之間的區(qū)別與聯(lián)系對(duì)編寫高質(zhì)量代碼至關(guān)重要,本文給大家介紹Java 中的 ==、equals()與hashCode()原理,感興趣的朋友一起看看吧

在 Java 開發(fā)中,==、equals() 和 hashCode() 是處理對(duì)象比較和哈希計(jì)算的核心元素,理解它們之間的區(qū)別與聯(lián)系對(duì)編寫高質(zhì)量代碼至關(guān)重要。

一、== 運(yùn)算符

== 是 Java 中的比較運(yùn)算符,用于比較兩個(gè)值是否相等,其行為取決于比較的是基本類型還是引用類型:

1. 比較基本數(shù)據(jù)類型

對(duì)于 int、double、char 等基本類型,== 比較的是實(shí)際存儲(chǔ)的值

int a = 10;
int b = 10;
System.out.println(a == b); // true,值相等
double c = 3.14;
double d = 3.14;
System.out.println(c == d); // true

2. 比較引用數(shù)據(jù)類型

對(duì)于對(duì)象(引用類型),== 比較的是對(duì)象在內(nèi)存中的地址(即是否為同一個(gè)對(duì)象):

因?yàn)閖ava是值傳遞,這里可能是地址的副本進(jìn)行比較,根據(jù)這個(gè)副本也可以修改對(duì)象。

但是,這種比較不關(guān)心變量是否相同,只關(guān)心引用的對(duì)象是否相同。

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false,兩個(gè)不同的對(duì)象,地址不同
String s3 = s1;
System.out.println(s1 == s3); // true,指向同一個(gè)對(duì)象

注意點(diǎn)

  • 基本類型的包裝類(如 IntegerDouble)使用 == 時(shí),同樣比較地址而非值(除非觸發(fā)常量池緩存機(jī)制)
  • 基本數(shù)據(jù)類型不能與null比較,因?yàn)榛緮?shù)據(jù)類型就沒有null這個(gè)值。
  • null == null 結(jié)果為 true,任何對(duì)象與 null 用 == 比較都為 false

(1)基本類型 vs 包裝類(==比較)

  • 包裝類會(huì)自動(dòng)拆箱為基本類型,比較的是值。
    例:int a = 5; Integer b = 5; System.out.println(a == b); // true

(2)包裝類 vs 包裝類(==比較)

  • 比較的是對(duì)象的引用地址(是否為同一個(gè)對(duì)象),而非值。
  • 注意:Java 對(duì)Integer[-128, 127]范圍內(nèi)有緩存機(jī)制,超出此范圍會(huì)創(chuàng)建新對(duì)象。
    例 1:Integer a = 100; Integer b = 100; System.out.println(a == b); // true(使用緩存)
    例 2:Integer a = 200; Integer b = 200; System.out.println(a == b); // false(新對(duì)象)
  • 當(dāng)其中一個(gè)為new Integer(1)時(shí),是強(qiáng)制顯式創(chuàng)建一個(gè)對(duì)象,這里會(huì)開辟一個(gè)新的對(duì)象,即使緩存中有也不會(huì)使用。這時(shí)候比較就是false

二、equals () 方法

equals() 是 Object 類定義的實(shí)例方法,用于判斷兩個(gè)對(duì)象是否 "相等",默認(rèn)行為與 == 一致,比較的是對(duì)象的內(nèi)存地址(即是否為同一個(gè)對(duì)象)。

1. 默認(rèn)實(shí)現(xiàn)(Object 類中)

public boolean equals(Object obj) {
    return (this == obj); // 本質(zhì)就是用 == 比較地址
}

2. 重寫后的常見實(shí)現(xiàn)

多數(shù)類會(huì)重寫 equals() 方法,使其比較對(duì)象的內(nèi)容而非地址,例如 String 類:

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1.equals(s2)); // true,內(nèi)容相同
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.equals(list2)); // true,兩個(gè)空列表內(nèi)容相同

3. 重寫 equals () 的規(guī)范

重寫 equals() 時(shí)需遵循以下規(guī)則(來自《Effective Java》):

  • 自反性x.equals(x) 必須返回 true
  • 對(duì)稱性:若 x.equals(y) 為 true,則 y.equals(x) 也必須為 true
  • 傳遞性:若 x.equals(y) 和 y.equals(z) 為 true,則 x.equals(z) 也必須為 true
  • 一致性:多次調(diào)用 x.equals(y) 應(yīng)返回相同結(jié)果(前提是對(duì)象未被修改)
  • 非空性x.equals(null) 必須返回 false

4. 重寫示例(自定義類)

public class User {
    private String id;
    private String name;
    // 構(gòu)造方法、getter、setter 省略
    @Override
    public boolean equals(Object o) {
        // 1. 自身判斷
        if (this == o) return true;
        // 2. 類型判斷
        if (o == null || getClass() != o.getClass()) return false;
        // 3. 內(nèi)容比較
        User user = (User) o;
        return Objects.equals(id, user.id) && 
               Objects.equals(name, user.name);
    }
}

注意點(diǎn)

  • 若調(diào)用者是null(如null.equals(obj)):必拋空指針異常。
  • 若參數(shù)是null(如obj.equals(null)):返回false(因?yàn)?code>null不是任何對(duì)象的實(shí)例)。
  • 如果兩個(gè)對(duì)象通過equals()比較返回true,那么它們的hashCode()必須返回相同的值;反之,hashCode()不同的對(duì)象,equals()必須返回false

三、hashCode () 方法

hashCode() 也是 Object 類的方法,返回一個(gè) int 類型的哈希值,主要用于哈希表(如 HashMap、HashSet)中快速定位對(duì)象。

1. 基本作用

  • 哈希值用于確定對(duì)象在哈希表中的存儲(chǔ)位置
  • 提高哈希表的查找效率(理想情況下,不同對(duì)象應(yīng)具有不同哈希值)

2. 默認(rèn)實(shí)現(xiàn)

Object 類的 hashCode() 返回對(duì)象的內(nèi)存地址轉(zhuǎn)換后的整數(shù)(不同 JVM 實(shí)現(xiàn)可能不同)。

3. 重寫原則

關(guān)鍵規(guī)則如果兩個(gè)對(duì)象通過 equals() 比較相等,則它們的 hashCode() 必須返回相同的值。反之則不成立(不同對(duì)象也可能有相同哈希值,即哈希沖突)。

這是因?yàn)楣1碓谂袛鄬?duì)象是否存在時(shí),會(huì)先通過哈希值定位,再用 equals() 精確比較。若違反此規(guī)則,會(huì)導(dǎo)致哈希表無法正常工作:

// 反例:equals相等但hashCode不同
class BadExample {
    private int value;
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BadExample that = (BadExample) o;
        return value == that.value;
    }
    @Override
    public int hashCode() {
        return (int) (Math.random() * 1000); // 錯(cuò)誤實(shí)現(xiàn):相同對(duì)象可能返回不同哈希值
    }
}

4. 正確的重寫實(shí)現(xiàn)

通常結(jié)合對(duì)象中參與 equals() 比較的字段來計(jì)算哈希值:

@Override
public int hashCode() {
    // 使用 Objects.hash() 簡化實(shí)現(xiàn)
    return Objects.hash(id, name);
}
// 等價(jià)于手動(dòng)計(jì)算
@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
}

使用 31 是因?yàn)樗且粋€(gè)質(zhì)數(shù),能減少哈希沖突,且 31 * i 可以被優(yōu)化為 (i << 5) - i,提高計(jì)算效率。

四、三者之間的關(guān)系總結(jié)

  1. == 與 equals()

    • 未重寫 equals() 時(shí),兩者功能一致(比較地址)
    • 重寫 equals() 后,== 仍比較地址,equals() 比較內(nèi)容
  2. equals() 與 hashCode()

    • 核心約定:equals() 為 true → hashCode() 必須相等
    • 反之不成立:hashCode() 相等 → equals() 不一定為 true(哈希沖突)
    • 實(shí)際應(yīng)用:在哈希集合中,先通過 hashCode() 定位,再用 equals() 確認(rèn)
  3. 使用場(chǎng)景

    • 比較基本類型 → 用 ==
    • 比較對(duì)象地址 → 用 ==
    • 比較對(duì)象內(nèi)容 → 用 equals()
    • 自定義類用于哈希表 → 必須同時(shí)重寫 equals() 和 hashCode()

五、常見面試題解析

  • 為什么重寫 equals () 必須重寫 hashCode ()?
    • 答:為了保證希表(如 哈HashMap)的正確性。如果兩個(gè)對(duì)象 equals 相等但 hashCode 不同,會(huì)導(dǎo)致它們?cè)诠1碇斜淮鎯?chǔ)在不同位置,從而出現(xiàn) "相同對(duì)象卻被視為不同" 的情況。
  • String 類的 == 和 equals () 有什么區(qū)別?
    • 答:== 比較對(duì)象地址,equals() 比較字符串內(nèi)容。由于字符串常量池的存在,"abc" == "abc" 為 true,但 new String("abc") == new String("abc") 為 false。
  • Integer 類型用 == 比較時(shí)要注意什么?
    • 答:Integer 對(duì) -128~127 范圍的值有緩存,因此 Integer a = 100; Integer b = 100; a == b 為 true,但超出此范圍則為 false,應(yīng)始終用 equals() 比較值。

到此這篇關(guān)于一文讀懂 Java 中的 ==、equals () 與 hashCode ()原理與避坑指南的文章就介紹到這了,更多相關(guān)java ==、equals () 與 hashCode ()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)深度搜索DFS算法詳解

    Java實(shí)現(xiàn)深度搜索DFS算法詳解

    深度優(yōu)先搜索是一種在開發(fā)爬蟲早期使用較多的方法。它的目的是要達(dá)到被搜索結(jié)構(gòu)的葉結(jié)點(diǎn)。這篇文章主要介紹了基于Java實(shí)現(xiàn)深度優(yōu)先搜索(DFS)算法,需要的朋友可以參考一下
    2021-12-12
  • SpringCloud服務(wù)接口調(diào)用OpenFeign及使用詳解

    SpringCloud服務(wù)接口調(diào)用OpenFeign及使用詳解

    這篇文章主要介紹了SpringCloud服務(wù)接口調(diào)用——OpenFeign,在學(xué)習(xí)Ribbon時(shí),服務(wù)間調(diào)用使用的是RestTemplate+Ribbon實(shí)現(xiàn),而Feign在此基礎(chǔ)上繼續(xù)進(jìn)行了封裝,使服務(wù)間調(diào)用變得更加方便,需要的朋友可以參考下
    2023-04-04
  • Java abstract class 與 interface對(duì)比

    Java abstract class 與 interface對(duì)比

    這篇文章主要介紹了 Java abstract class 與 interface對(duì)比的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 詳解Springboot應(yīng)用中設(shè)置Cookie的SameSite屬性

    詳解Springboot應(yīng)用中設(shè)置Cookie的SameSite屬性

    Chrome 51 開始,瀏覽器的 Cookie 新增加了一個(gè)SameSite屬性,用來防止 CSRF 攻擊和用戶追蹤。今天通過本文給大家介紹Springboot應(yīng)用中設(shè)置Cookie的SameSite屬性,感興趣的朋友一起看看吧
    2022-01-01
  • spring-boot-maven-plugin插件爆紅問題及解決方案

    spring-boot-maven-plugin插件爆紅問題及解決方案

    這篇文章主要介紹了spring-boot-maven-plugin插件爆紅問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • @Autowired注解以及失效的幾個(gè)原因圖文詳解

    @Autowired注解以及失效的幾個(gè)原因圖文詳解

    在微服務(wù)項(xiàng)目中,會(huì)遇到@Autowired注解失效的情況,下面這篇文章主要給大家介紹了關(guān)于@Autowired注解以及失效的幾個(gè)原因的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • Spring整合quartz做定時(shí)任務(wù)的示例代碼

    Spring整合quartz做定時(shí)任務(wù)的示例代碼

    這篇文章主要介紹了在spring項(xiàng)目使用quartz做定時(shí)任務(wù),首先我這里的項(xiàng)目已經(jīng)是一個(gè)可以跑起來的完整項(xiàng)目,web.xml里面的配置我就不貼出來了,具體實(shí)例代碼跟隨小編一起看看吧
    2022-01-01
  • mybatis中批量更新多個(gè)字段的2種實(shí)現(xiàn)方法

    mybatis中批量更新多個(gè)字段的2種實(shí)現(xiàn)方法

    當(dāng)我們使用mybatis的時(shí)候,可能經(jīng)常會(huì)碰到一批數(shù)據(jù)的批量更新問題,因?yàn)槿绻粭l數(shù)據(jù)一更新,那每一條數(shù)據(jù)就需要涉及到一次數(shù)據(jù)庫的操作,本文主要介紹了mybatis中批量更新多個(gè)字段的2種實(shí)現(xiàn)方法,感興趣的可以了解一下
    2023-09-09
  • Java?List<JSONObject>中的數(shù)據(jù)如何轉(zhuǎn)換為List<T>

    Java?List<JSONObject>中的數(shù)據(jù)如何轉(zhuǎn)換為List<T>

    這篇文章主要介紹了Java?List<JSONObject>中的數(shù)據(jù)如何轉(zhuǎn)換為List<T>問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Java Semaphore實(shí)現(xiàn)高并發(fā)場(chǎng)景下的流量控制

    Java Semaphore實(shí)現(xiàn)高并發(fā)場(chǎng)景下的流量控制

    在java開發(fā)的工作中是否會(huì)出現(xiàn)這樣的場(chǎng)景,你需要實(shí)現(xiàn)一些異步運(yùn)行的任務(wù),該任務(wù)可能存在消耗大量內(nèi)存的情況,所以需要對(duì)任務(wù)進(jìn)行并發(fā)控制。本文將介紹通過Semaphore類優(yōu)雅的實(shí)現(xiàn)并發(fā)控制,感興趣的可以了解一下
    2021-12-12

最新評(píng)論