搜尋
首頁Javajava教程關於java覆蓋equals更深層的方法概述

最近和同事談到equals和==的差別。這其實是個非常老套簡單的問題,但當你要親自覆蓋equals方法時,才發現,有一些你不知道卻又不得不知道的事。覆蓋equals,講究很多。儘管Object是一個很具體的類,但他的主要作用還是為了擴展。他的所有非final方法都有明確的通用約定。因為他們被設計成要被覆蓋的方法。任何一個類,在覆寫equals、hashCode、toString、clone、finalize時,都有責任遵守這些方法的通用約定。如果不能做到這一點,那麼當多個類別組合時將難以發揮我們期望的效果。

不覆寫equals方法


覆寫equals方法看起來簡單,但是有許多覆寫方法會導致錯誤。最容易避免這種錯誤的方法就是不覆寫equals,這種情況下每個類別的實例都只與自身相等。那麼在什麼情況下我們可以選擇不覆寫equals方法呢?

類別的每個實例本質上是唯一的

對於代表活動實體而不是值的類別確實如此,例如每個執行緒實例。我們用equals方法比較他是毫無意義的,因為每個線程都是唯一的。在這種情況下,我們不用覆寫equals方法,因為Object類別中的equals已經完全夠用了。

Object類別中equals方法實作:

 public boolean equals(Object obj) { return (this == obj);  }

#不關心類別是否需要邏輯相等的判斷

有些類別是一些“數值類別”,比較大小,數學運算是這些類別的本職工作。在這種情況下,需要我們將類別中存放的數值進行比較,需要進行邏輯相等的判斷。除此之外的類,很大部分類別沒有「一個是否等於另外一個」的概念。這種不關心邏輯相等的類別不需要覆寫equals方法。

超類別實作的equals對子類別適用

舉個例子,繼承了AbstractSet類別的HashSet類別在equals方法上並沒有任何區別,那麼HashSet直接使用AbstractSet的equals方法即可。

覆寫equals方法

與上面的內容相反的,我們需要覆寫equals方法的情況就是:如果類別具有自己的邏輯相等的概念,並且父類沒有進行可用的equals方法覆蓋。這時需要我們親自進行覆蓋。

集合中equals方法的等價關係


equals方法實現了等價關係。離散數學中學過等價關係的概念,對於一個R上的二元關係,如果它滿足自反對稱和傳遞,那麼他就是等價的。讓我們來具體分析一下equals和這三種性質的關係。

自反性 : 對於任何非null的參考值x,x.equals(x)必須傳回true

對稱性 : 對於任何非null的參考值x和y,當且僅當y.equals(x)回傳true時,x.equals(y)必定傳回true

傳遞性 : 對於任何非null的參考值x、y和z,如果x.equals(y)回傳true、y.equals(z)也回傳true,那麼x.equals(z)必定回傳true。

自反:∀ a ∈A, => (a, a) ∈ R
對稱性:(a, b) ∈R∧ a ≠ b => (b, a) ∈R
傳遞性:(a, b)∈R,(b, c)∈R =>(a, c)∈R

對比這三個性質,沒有任何問題。由此可得,equals方法實現了等價關係。

如何寫equals方法


Object的equals方法只是簡單的看看位址,這顯然不可能滿足我們的要求。那麼在自己編寫equals方法進行覆蓋時如何保證編寫出高品質的,邏輯比較的方法呢? equals的編寫可以概括為下面四個步驟:

1.使用==運算子檢查參數是否只是物件的參考
如果結果相等則傳回true,說明x與y是一個物件的不同引用,不需要再進行判斷了。

2.使用instanceof運算子檢查參數是否類型正確
如果結果不是正確的類型則傳回false,因為我們的equals方法是繼承自Object類別的,所以參數的型別無法避免的是Object,我們先使用instanceof對參數做型別判斷,如果型別都不正確,就不用進行下一步判斷了。

3.把參數轉換成正確的型別
因為之前做了偵測,所以這一步的型別轉換沒有問題。

4.對每個類別中需要邏輯比較的域值進行判斷
已經確保x和y是相同類型的不同實例,將需要判斷的邏輯比較的域值取出進行比較判斷即可。如果全部正確則回傳true,否則傳回false。

關於實作的equals需要注意的問題


當寫完equals方法後,一定要反覆的判斷是否符合自反性,對稱性和傳遞性。不僅僅如此,在確保等價的情況下,編寫equals方法時還有一些值得注意的事情,我們需要以此改進。

覆寫equals方法時總是要覆寫hashCode方法
如果我們在寫有關雜湊的類別時,必須在覆寫equals方法時覆寫hashCode方法。因為在散列表中,邏輯相同的物件應該具有相同的雜湊碼。舉個比較簡單的例子:將String存入HashSet,有可能兩個內容相同的String字串用==判斷為false,但是他們在HashSet中只存在了一份。這就是因為邏輯相同的String擁有這相同的hashCode。
普遍性的,如果你為你的類別覆寫了equals方法,那麼證明在某種情況下會有兩個不同物件是邏輯相等的。此時如果與雜湊相關,那麼這兩個物件需要相同的hashCode。所以覆寫equals方法時總是要覆寫hashCode方法。

不要讓equals方法過於智慧
如果我們只是簡單的按照上面的實作流程來寫equals的方法,既符合規定也不會導致奇怪的錯誤。但如果我們非要去追求各種、花俏的等價關係,而把程式碼搞得臃腫不堪,那麼既違反了高內聚的初衷,也會讓程式碼出一些莫名其妙的錯誤。

不要將equals方法的參數類型弄錯
說出來可能感覺好笑,但這確實是會發生的情況。修改了參數類型之後的equals方法已完全於Object類別沒有了關係,編譯器不會報錯,留下的只是給程式設計師無盡的頭痛。如果無法意識到參數類型是Object,很有可能花幾個小時也搞不清楚程式為什麼不能正常運作。

#

最近和同事談到equals和==的差別。這其實是個非常老套簡單的問題,但當你要親自覆蓋equals方法時,才發現,有一些你不知道卻又不得不知道的事。覆蓋equals,講究很多。儘管Object是一個很具體的類,但他的主要作用還是為了擴展。他的所有非final方法都有明確的通用約定。因為他們被設計成要被覆蓋的方法。任何一個類,在覆寫equals、hashCode、toString、clone、finalize時,都有責任遵守這些方法的通用約定。如果不能做到這一點,那麼當多個類別組合時將難以發揮我們期望的效果。

不覆寫equals方法


覆寫equals方法看起來簡單,但是有許多覆寫方法會導致錯誤。最容易避免這種錯誤的方法就是不覆寫equals,這種情況下每個類別的實例都只與自身相等。那麼在什麼情況下我們可以選擇不覆寫equals方法呢?

類別的每個實例本質上是唯一的

對於代表活動實體而不是值的類別確實如此,例如每個執行緒實例。我們用equals方法比較他是毫無意義的,因為每個線程都是唯一的。在這種情況下,我們不用覆寫equals方法,因為Object類別中的equals已經完全夠用了。

Object類別中equals方法實作:

 public boolean equals(Object obj) { return (this == obj);  }

#不關心類別是否需要邏輯相等的判斷

有些類別是一些“數值類別”,比較大小,數學運算是這些類別的本職工作。在這種情況下,需要我們將類別中存放的數值進行比較,需要進行邏輯相等的判斷。除此之外的類,很大部分類別沒有「一個是否等於另外一個」的概念。這種不關心邏輯相等的類別不需要覆寫equals方法。

超類別實作的equals對子類別適用

舉個例子,繼承了AbstractSet類別的HashSet類別在equals方法上並沒有任何區別,那麼HashSet直接使用AbstractSet的equals方法即可。

覆寫equals方法

與上面的內容相反的,我們需要覆寫equals方法的情況就是:如果類別具有自己的邏輯相等的概念,並且父類沒有進行可用的equals方法覆蓋。這時需要我們親自進行覆蓋。

集合中equals方法的等價關係


equals方法實現了等價關係。離散數學中學過等價關係的概念,對於一個R上的二元關係,如果它滿足自反對稱和傳遞,那麼他就是等價的。讓我們來具體分析一下equals和這三種性質的關係。

自反性 : 對於任何非null的參考值x,x.equals(x)必須傳回true

對稱性 : 對於任何非null的參考值x和y,當且僅當y.equals(x)回傳true時,x.equals(y)必定傳回true

傳遞性 : 對於任何非null的參考值x、y和z,如果x.equals(y)回傳true、y.equals(z)也回傳true,那麼x.equals(z)必定回傳true。

自反:∀ a ∈A, => (a, a) ∈ R
對稱性:(a, b) ∈R∧ a ≠ b => (b, a) ∈R
傳遞性:(a, b)∈R,(b, c)∈R =>(a, c)∈R

對比這三個性質,沒有任何問題。由此可得,equals方法實現了等價關係。

如何寫equals方法


Object的equals方法只是簡單的看看位址,這顯然不可能滿足我們的要求。那麼在自己編寫equals方法進行覆蓋時如何保證編寫出高品質的,邏輯比較的方法呢? equals的編寫可以概括為下面四個步驟:

1.使用==運算子檢查參數是否只是物件的參考
如果結果相等則傳回true,說明x與y是一個物件的不同引用,不需要再進行判斷了。

2.使用instanceof運算子檢查參數是否類型正確
如果結果不是正確的類型則傳回false,因為我們的equals方法是繼承自Object類別的,所以參數的型別無法避免的是Object,我們先使用instanceof對參數做型別判斷,如果型別都不正確,就不用進行下一步判斷了。

3.把參數轉換成正確的型別
因為之前做了偵測,所以這一步的型別轉換沒有問題。

4.對每個類別中需要邏輯比較的域值進行判斷
已經確保x和y是相同類型的不同實例,將需要判斷的邏輯比較的域值取出進行比較判斷即可。如果全部正確則回傳true,否則傳回false。

關於實作的equals需要注意的問題


當寫完equals方法後,一定要反覆的判斷是否符合自反性,對稱性和傳遞性。不僅僅如此,在確保等價的情況下,編寫equals方法時還有一些值得注意的事情,我們需要以此改進。

覆寫equals方法時總是要覆寫hashCode方法
如果我們在寫有關雜湊的類別時,必須在覆寫equals方法時覆寫hashCode方法。因為在散列表中,邏輯相同的物件應該具有相同的雜湊碼。舉個比較簡單的例子:將String存入HashSet,有可能兩個內容相同的String字串用==判斷為false,但是他們在HashSet中只存在了一份。這就是因為邏輯相同的String擁有這相同的hashCode。
普遍性的,如果你為你的類別覆寫了equals方法,那麼證明在某種情況下會有兩個不同物件是邏輯相等的。此時如果與雜湊相關,那麼這兩個物件需要相同的hashCode。所以覆寫equals方法時總是要覆寫hashCode方法。

不要讓equals方法過於智慧
如果我們只是簡單的按照上面的實作流程來寫equals的方法,既符合規定也不會導致奇怪的錯誤。但如果我們非要去追求各種、花俏的等價關係,而把程式碼搞得臃腫不堪,那麼既違反了高內聚的初衷,也會讓程式碼出一些莫名其妙的錯誤。

不要將equals方法的參數類型弄錯
說出來可能感覺好笑,但這確實是會發生的情況。修改了參數類型之後的equals方法已完全於Object類別沒有了關係,編譯器不會報錯,留下的只是給程式設計師無盡的頭痛。如果無法意識到參數類型是Object,很有可能花幾個小時也搞不清楚程式為什麼不能正常運作。

以上是關於java覆蓋equals更深層的方法概述的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。