Java對象的比較——equals方法,Comparable接口,Comparator接口

Java對象的比較——equals方法,Comparable接口,Comparator接口

  • 1. equals方法
  • 2. Comparable接口
  • 3. Comparator接口

1. equals方法

在判斷兩個整數是否相同時,我們可以使用以下方式:

System.out.println(1 == 2);
System.out.println(1 == 1);

如果輸出true,則說明這兩個整數相同;如果輸出false,則說明這兩個整數不相同

那么,如果將==用于判斷兩個對象,又會是怎樣的情況呢?我們直接敲代碼來看看!

public class Dog {private String name;private int age;public Dog(String name, int age) {this.name = name;this.age = age;}
}
public class Test1 {public static void main(String[] args) {Dog dog1 = new Dog("zhangsan",1);Dog dog2 = new Dog("zhangsan",1);System.out.println(dog1 == dog2);}
}

運行結果:
在這里插入圖片描述
當運行這段代碼時,我們發現輸出的是false。明明dog1和dog2的屬性都一模一樣,為什么輸出false呢?莫慌,且聽我慢慢道來!
在這里插入圖片描述
畫圖來分析,dog1和dog2中存放的值并不相同,因此dog1 != dog2。而你之所以認為輸出的應該是true,是因為你認為,兩個對象的屬性完全一致,所以dog1 == dog2.其實,并不是這樣的,==判斷的并不是對象的屬性是否一致,而是判斷兩個引用指向的是否是同一個對象!

在Java中,一切皆對象。而dog1和dog2是對象的引用。==判斷的并不是對象的屬性是否一致,而是判斷兩個引用指向的是否是同一個對象!

因此,只有當兩個引用指向同一對象才返回true;而如果兩個引用指向不同的對象,即使兩個對象的屬性完全相同,返回依舊是false!

總結:

  • 如果==左右兩邊是基本數據類型變量,比較的是變量中的值是否相同
  • 如果==左右兩邊是引用數據類型變量,比較的是引用變量中的值是否相同,而引用變量中存放的是對象的地址,所以比較的就是引用變量中存放的地址是否相同(即判斷兩個引用指向的是否是同一個對象!)

理解了這一點,學習equals方法就簡單多了!我們先來看看equals方法的原型,equals方法在Object類中
在這里插入圖片描述
有沒有發現,equals方法,返回正是剛剛所講的內容,說明equals方法默認就是判斷兩個引用指向的是否是同一個對象!

注意: equals方法的返回值是boolean類型!

再來嘗試運行這段代碼:

public class Test1 {public static void main(String[] args) {Dog dog1 = new Dog("zhangsan",1);Dog dog2 = new Dog("zhangsan",1);System.out.println(dog1.equals(dog2));}
}

運行結果依舊是false


那么,問題來了,如果我們想通過比較兩個對象的屬性是否相等,如果相等,從邏輯上就說明他們就是相等的,該怎么辦呢?

我們知道Object類是一切類的父類,而equals方法在Object類中,是不是就通過可以重寫equals方法,從而達到自定義比較方式的目的!

下面就演示重寫equals方法,規則:如果兩個對象的屬性完全一致,則返回true;否則放回false

public class Dog {private String name;private int age;public Dog(String name, int age) {this.name = name;this.age = age;}public boolean equals(Object obj) {Dog tmp = (Dog)obj;return this.name.equals(tmp.name) && this.age == tmp.age;}
}
public class Test1 {public static void main(String[] args) {Dog dog1 = new Dog("zhangsan",1);Dog dog2 = new Dog("zhangsan",1);System.out.println(dog1.equals(dog2));}
}

這時運行代碼,輸出的就是true!

這時,有人可能就有疑問了,為什么名字比較要用equals方法,其實這里的equals方法并非Dog類中的equals方法,而是String類中的equals方法,用來判斷兩個字符串是否相等

String類中的equals方法原型:
在這里插入圖片描述
另外,編譯器可以幫我們自動生成equals方法,第一步按住alt+insert
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
一路點下去,就可以生成equals方法,除此之外,還生成了hashCode方法
在這里插入圖片描述

2. Comparable接口

通過重寫equals方法,我們可以從邏輯上去判斷兩個對象是否相同。但是如果要去比較兩個對象的大小,又該怎么去比較呢?對象的屬性那么多,通過什么屬性去比較呢?這時就需要講到Comparable接口!

在這里插入圖片描述
當我們在Student類后加上Comparable接口時,發現會報錯,這是為什么呢?我們按住CTRL鍵,再鼠標左擊Comparable,進入源碼
在這里插入圖片描述
我們發現,Comparable接口中還有個compareTo抽象方法,因此當我們在Student類要實現這個方法,除此之外,Comparable接口后還有個,這是泛型,我們需要比較什么類型的對象,就在實現接口時把T改成什么
在這里插入圖片描述
由編譯器自動生成實現compareTo方法的代碼后:
在這里插入圖片描述
我們就需要書寫compareTo的方法體,那怎么書寫呢?你想根據哪個對象的屬性進行比較,就怎么書寫。


比如,我現在想根據對象的年齡進行比較
在這里插入圖片描述
下面進行測試:

public class Student implements Comparable<Student>{private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic int compareTo(Student o) {return this.age-o.age;}
}
public class Test {public static void main(String[] args) {Student student1 = new Student("zhangsan", 18);Student student2 = new Student("lisi", 10);System.out.println(student1.compareTo(student2));}
}

運行結果:
在這里插入圖片描述
返回的是一個正數,說明根據年齡比較,student1大于student2


再比如,我不想根據年齡比較了,我想根據姓名比較,這時就不能用簡單的this.name-o.name了,因為name是一個String類型,不能通過這樣的方式進行比較
在這里插入圖片描述
方法里的compareTo指并不是在Student類中具體實現的這個compareTo,而是String類中的conpareTo,用于字符串的比較,它的底層是和C語言的strcmp是一樣的,返回的是兩個字母的ASCII 碼的差值
String類中的compareTo方法


那么,問題來了,前面我們比較的只有兩個對象,如果需要比較多個對象呢,改怎么辦呢?這時候就需要用到數組來存放對象,用Arrays里的排序方法進行排序

當我們寫下以下代碼:

public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class Test {public static void main(String[] args) {Student[] students = new Student[]{new Student("zhangsan",18),new Student("lisi", 10),new Student("wangwu", 20)};System.out.println("排序前:" + Arrays.toString(students));Arrays.sort(students);System.out.println("排序后:" + Arrays.toString(students));}
}

當我們運行代碼后,發現會出現異常
在這里插入圖片描述
在這里插入圖片描述

這里需要用到強轉,而Student類并沒有去實現Comparable接口,因此會導致強轉失敗!這就是異常所在!所以,我們需要在Student類中實現Comparable接口

public class Student implements Comparable<Student>{private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {return this.age-o.age;}
}

在這里插入圖片描述

當我們再次去運行代碼時,會發現排序后是根據年齡從小到大排序的,這和Student類中實現的compareTo難道有關系?答案是正確的

假如我們想按照年齡從大到小去排序,就做出如下更改
在這里插入圖片描述
調換順序即可,再次運行代碼:
在這里插入圖片描述


假如想根據年齡去比呢?

public class Student implements Comparable<Student>{private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {return this.name.compareTo(o.name);}
}
public class Test1 {public static void main(String[] args) {Student[] students = new Student[]{new Student("zhangsan",10),new Student("lisi", 18),new Student("wangwu", 9)};System.out.println("排序前:" + Arrays.toString(students));Arrays.sort(students);System.out.println("排序后:" + Arrays.toString(students));}
}

3. Comparator接口

在前面使用Comparable接口來實現對象的比較時,我們不難發現,這個比較方法并不靈活,只能固定地通過一種方式去比較,那么如果我們有的時候想通過年齡比較,有的時候想通過姓名比較,這個接口就無法實現了,這時地解決辦法就是,換一個接口,用Comparator接口來實現!

這時,我們分別寫兩個類——NameComparator和AgeComparator,代表分別通過姓名比較和通過年齡比較。并且這兩個類都要實現Comparator接口!

import java.util.Comparator;public class NameComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.getName().compareTo(o2.getName());//姓名通過compareTo方法進行比較}
}
import java.util.Comparator;public class AgeComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.getAge() - o2.getAge();}
}

注意: 實現Comparator接口需要重寫的時compare方法,不是compareTo方法!實現Comparable接口重寫的才是compareTo方法!

學生類如下:

public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

測試一下代碼:

import java.util.Arrays;public class Test {public static void main(String[] args) {//兩個對象的比較AgeComparator ageComparator = new AgeComparator();NameComparator nameComparator = new NameComparator();Student student1 = new Student("zhangsan", 20);Student student2 = new Student("lisi", 30);System.out.println("根據年齡比:" + ageComparator.compare(student1, student2));System.out.println("根據姓名比:" + nameComparator.compare(student1, student2));//一組對象的比較Student[] students = new Student[]{new Student("zhangsan", 10),new Student("lisi", 18),new Student("wangwu", 9)};System.out.println("排序前:" + Arrays.toString(students));Arrays.sort(students, ageComparator);System.out.println("根據年齡排序后:" + Arrays.toString(students));Arrays.sort(students, nameComparator);System.out.println("根據姓名排序后:" + Arrays.toString(students));}
}

分析兩個對象的比較:
在這里插入圖片描述
這里,我們創建了一個AgeComparator和一個NameComparator對象,用來表示是通過年齡比較還是通過姓名比較。注意最后兩個Student類對象的比較方法

分析一組對象的比較:
在這里插入圖片描述
我們發現,在用Arrays.sort排序時,里面還加上了一個ageComparator對象(或NameComparator對象),通過這個對象,可以控制通過什么方式去比較,當使用Arrays對數組進行排序時,就會調用ageComparator(或NameComparator)里的compare方法依次將數組里的對象進行比較

最后,運行結果:
在這里插入圖片描述


請添加圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20185.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20185.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20185.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安防綜合管理系統EasyCVR平臺GA/T1400視圖庫:基于XML的消息體格式

GA/T 1400標準的應用范圍廣泛&#xff0c;涵蓋了公安系統的視頻圖像信息應用系統&#xff0c;如警務綜合平臺、治安防控系統、交通管理系統等。在視頻監控系統中&#xff0c;GA/T 1400公安視圖庫的對接是實現視頻圖像信息傳輸、處理和管理的重要環節。 以視頻匯聚EasyCVR視頻監…

【SpringBoot】怎么在一個大的SpringBoot項目中創建多個小的SpringBoot項目,從而形成子父依賴

父子項目工程創建 步驟 先創建父項目 具體操作步驟請看本文章&#xff1a;使用maven工程創建spring boot項目 創建子項目 file- project structure module–new module 剩下步驟請看創建父工程時的操作使用maven工程創建spring boot項目 應用 確認即可 之后創建啟動類…

ARM32開發——LED驅動開發

&#x1f3ac; 秋野醬&#xff1a;《個人主頁》 &#x1f525; 個人專欄:《Java專欄》《Python專欄》 ??心若有所向往,何懼道阻且長 文章目錄 需求介紹現實問題需求分析測試案例構建BSP驅動構建業務實現 需求介紹 開發版中有4個燈&#xff0c;現在需要用4個燈顯示充電情況&a…

618大促有哪些好物是最值得入手的的?請收下這份618必買好物清單!

最近聊的最多的話題就是618&#xff0c;年中購物大狂歡馬上來了&#xff01;&#xff01;今天整理了一下之前購買的好物&#xff0c;發現相比之前的價格真的是太劃算了&#xff0c;趕緊分享出來給大家&#xff0c;趁著這個大促趕緊多存入手~ 推薦1、南卡Neo 2——不傷耳黑科技…

SPHINX的輸出文檔格式

SPHINX的輸出文檔格式 SPHINX的輸出文檔格式更多信息 SPHINX的輸出文檔格式 用rst編寫&#xff0c;然后用sphinx-build進行編譯&#xff0c;還是效果相當不錯地&#xff0c;只要掌握了格式&#xff0c;可以一次編譯&#xff0c;多種格式輸出&#xff0c;主要是用的可能是html和…

記一次netty客戶端的開發

背景 近日要開發一個tcp客戶端程序去對接上游廠商的數據源&#xff0c;決定使用netty去處理&#xff0c;由于很久沒有開發過netty了&#xff0c;順便學習記錄下 netty搭建 考慮到我們需要多個client去對接server服務&#xff0c;所以我們定義一個公共的AbstractNettyClient父…

機器學習:人工智能中實現自動化決策與精細優化的核心驅動力

機器學習在人工智能中確實扮演著實現自動化決策與精細優化的核心驅動力角色。以下是關于這一點的詳細分析: 一、機器學習在自動化決策中的應用 數據驅動:機器學習依賴于大量的數據來進行模型訓練和評估,從而確保決策的準確性。通過自動化數據分析和處理,機器學習能夠從海量…

LabVIEW與Arm控制器之間的通訊

LabVIEW是一個強大的圖形化編程環境&#xff0c;廣泛應用于自動化控制、數據采集和測試測量等領域。而Arm控制器則是嵌入式系統中常用的處理器架構&#xff0c;廣泛用于各種控制和計算任務。將LabVIEW與Arm控制器進行通訊控制&#xff0c;可以結合二者的優勢&#xff0c;實現高…

vue3 中可緩存的方法

場景&#xff1a;在列表中&#xff0c;有這么一個屬性&#xff0c;需要通過同行的其他屬性&#xff0c;進行復雜的計算&#xff0c;才能得出&#xff0c;如果我們用方法&#xff0c;然后傳參&#xff0c;得到這個屬性&#xff0c;那么每次更改列表后&#xff0c;每行都會重新計…

WordPress plugin MStore API SQL注入漏洞復現(CVE-2023-3077)

0x01 產品簡介 WordPress和WordPress plugin都是WordPress基金會的產品。WordPress是一套使用PHP語言開發的博客平臺。該平臺支持在PHP和MySQL的服務器上架設個人博客網站。WordPress plugin是一個應用插件。 0x02 漏洞概述 WordPress plugin MStore API 3.9.8 版本之前存在S…

Linux 深入講解自動化構建工具

各位大佬好 &#xff0c;這里是阿川的博客 &#xff0c; 祝您變得更強 個人主頁&#xff1a;在線OJ的阿川 大佬的支持和鼓勵&#xff0c;將是我成長路上最大的動力 阿川水平有限&#xff0c;如有錯誤&#xff0c;歡迎大佬指正 Linux一系列的文章&#xff08;質量分均在93分…

配置arduino和ESP8266

首先準備好arduino 的IDE和ESP8266的驅動以及板子 1.安裝驅動&#xff0c;雙擊x64的版本驅動&#xff0c;安裝好以后&#xff0c;在資源管理器檢查端口&#xff0c;比如下下圖出現的COM4就是esp8266所使用的端口 2.安裝好arduino最好不要在路徑中存在中文符號&#xff0c;打開…

水滴式粉碎機:多功能飼料粉碎設備

飼料粉碎機是一種專門用于將各種飼料原料進行粉碎處理的機械設備。無論是玉米、小麥等谷物&#xff0c;還是豆粕、魚粉等動物性原料&#xff0c;甚至是一些粗纖維含量較高的秸稈、牧草等&#xff0c;都可以經過飼料粉碎機的處理&#xff0c;變成適合畜禽消化吸收的精細飼料。這…

521源碼-游戲源碼-2024卡牌回合自走棋手游《夢間集》推出全新Linux手工服務端

首款稀有卡牌回合自走棋手游《夢間集》推出全新Linux手工服務端整理 更多網站源碼&#xff0c;游戲源碼&#xff0c;學習教程&#xff0c;請點擊&#x1f449;-521源碼-&#x1f448;獲取最新資源 本游戲下載地址&#xff1a;2024卡牌回合自走棋手游《夢間集》推出全新Linux手…

【再探】設計模式—中介者模式、觀察者模式及模板方法模式

中介者模式讓多對多的復雜引用關系變成一對多&#xff0c;同時能通過中間類來封裝多個類中的行為&#xff0c;觀察者模式在目標狀態更新時能自動通知給訂閱者&#xff0c;模版方法模式則是控制方法的執行順序&#xff0c;子類在不改變算法的結構基礎上可以擴展功能實現。 1 中…

003 MySQL

文章目錄 左外連接、右外連接 的區別where/having的區別執行順序聚合 聚合函數MySQL約束事務一致性一致性的含義一致性在事務中的作用如何維護一致性 存儲引擎 Innodb MyIsam區別事務的ACID屬性數據庫的隔離級別MySQL中的并發問題1. 鎖等待和死鎖2. 并發沖突3. 臟讀、不可重復讀…

理解接口回調及其在 RabbitMQ 中的實際運用

介紹 接口回調是一種常見的編程模式&#xff0c;它在異步編程中發揮著重要作用。本文將通過一個簡單的示例介紹接口回調的概念和原理&#xff0c;并探討它在 RabbitMQ 中的實際應用。 接口回調的概念 接口回調是一種編程模式&#xff0c;用于在異步編程中實現回調機制。它允許…

ChatGPT AI專題資料合集【65GB】

介紹 ChatGPT & AI專題資料合集【65GB】 &#x1f381;【七七云享】資源倉庫&#xff0c;海量資源&#xff0c;無償分享√

stm32和esp32硬件資源上有什么區別 哪個更適合初學者

對于初學者來說&#xff0c;ESP32和STM32都有各自的優點和適用場景&#xff0c;但通常ESP32被認為是更適合初學者的選擇&#xff0c;原因如下&#xff1a; 內置無線通信&#xff1a;ESP32集成了WiFi和藍牙功能&#xff0c;這意味著初學者可以更容易地構建無線通信應用&#xff…

文件系統小冊(FusePosixK8s csi)【1 Fuse】

文件系統小冊&#xff08;Fuse&Posix&K8s csi&#xff09;【1 Fuse&#xff1a;用戶空間的文件系統】 Fuse(filesystem in userspace),是一個用戶空間的文件系統。通過fuse內核模塊的支持&#xff0c;開發者只需要根據fuse提供的接口實現具體的文件操作就可以實現一個文…