从源码出发:JAVA中对象的比较
?前言?
📘 博客主頁:to Keep博客主頁
🙆歡迎關注,👍點贊,📝留言評論
?首發時間:2022年2月26日
📨 博主碼云地址:博主碼云地址
📕參考書籍:java核心技術 卷1
📢編程練習:牛客網+力扣網
由于博主目前也是處于一個學習的狀態,如有講的不對的地方,請一定聯系我予以改正!!!
文章目錄
- 📕 PriorityQueue(優先級隊列)自定義類型對象的比較
- 📘 Comparable接口進行比較
- 📖 實現Comparable接口
- 📖源碼分析
- 📙 Comparator比較器進行比較
- 📖 構造Comparator比較器
- 📖 源碼分析
- 📖 匿名內部類的方式
- 📒 覆寫基類中的equals
- 📖注意事項:
- 📖缺陷:
- 🔓 總結
📕 PriorityQueue(優先級隊列)自定義類型對象的比較
在前面一遍文章中,我們了解到了什么是堆,為了簡單理解起見我們采用了基本數據類型(Integer)去進行比較,下面我們通過代碼來分析是如何實現自定義的類型進行比較。
我們首先定義一個學生類:
比較的結果:
之前我們了解到,優先級隊列的底層其實就是一個堆,我們為了滿足堆的性質,我們必須進行元素的比較,而我們自定義類型是無法直接比較的,需要我們通過指定的方法進行比較的。那么我們只有通過以下幾種方式進行自定義類型的比較!
📘 Comparable接口進行比較
📖 實現Comparable接口
我們首先必須先要在自定義類型中讓它實現Comparable接口,重寫comparable方法
public class Student implements Comparable<Student>{public int ID;public String name;public Student(int Id,String name){this.ID = Id;//學號this.name=name;//姓名}@Overridepublic int compareTo(Student o) {return this.ID-o.ID;}@Overridepublic String toString() {return "Student{" +"ID=" + ID +", name='" + name + '\'' +'}';} } class priority{public static void main(String[] args) {PriorityQueue<Student> priorityQueue = new PriorityQueue<>();Student student1 = new Student(1,"1號");Student student2 = new Student(2,"2號");priorityQueue.offer(student1);priorityQueue.offer(student2);System.out.println(priorityQueue);}}運行結果:
📖源碼分析
從以上的結果我們可以看出,這時候我們自定義的student1和student2兩個對象可以進行比較,下面我們通過源碼來分析以下是如何比較的:
首先,添加一個元素,源碼中的E表示的是泛型,這個之后我們會詳細講解,第一次傳過來的是student1,student1肯定不等于null,(modCount++無關我們分析),然后源碼中size=0;所以i是為0的,下一步判斷是否超過數組長度(因為優先級隊列底層就是一個數組)
如果超過了長度,原容量如果小于64,那么就會使2*oldcapacity+2擴容,否則就是1.5倍的擴容
然后此時size=1,由于i是為0的,那么就直接把student1直接放到queue[0]的位置
此時在加入student2,那么以上的執行步驟是一樣的,只不過student2放進來的時候i是不等于0的,所以只能執行else語句,else語句之后就會來到下列方法,而一開始的時候就將comparator置為null,所以只能執行else語句。
來到else語句之后將進行以下操作,先將student2強轉為可比較的類型,此時k是由i傳參過來的,那么k為1,e取出queue[0]中的值,也就是student1,符合if語句中的比較方式(也就是利用重寫comparable中student2中的學號減去student1中的學號差值),那么此時將會直接跳出循環,不進行交換,所以queue[1]=student2的值
📙 Comparator比較器進行比較
📖 構造Comparator比較器
class ID implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.ID-o2.ID;} } class priority{public static void main(String[] args) {ID id = new ID();PriorityQueue<Student> priorityQueue = new PriorityQueue<>(id);Student student1 = new Student(1,"1號");Student student2 = new Student(2,"2號");priorityQueue.offer(student1);priorityQueue.offer(student2);System.out.println(priorityQueue);}}注意這里在利用Comparator構造時,是需要添加比較器的引用的,否則Comparator默認為null,這樣的話是不能利用Comparator進行比較。
📖 源碼分析
經過對Comparatable源碼分析,其實Comparator的分析也是差不多的,就是在shifUp上要走的就是if語句了
過來之后,在調用方法比較,比較的方法其實是與Comparatable是一樣的
📖 匿名內部類的方式
這里并不是將Comparator這個接口實例化,而是寫成了一個匿名內部類的形式,至于具體什么是內部類,在之后的文章中我們將會解說。
運行結果:
在之后,其實這里的這個內部類可以轉化為lamada表達式,代碼會變的更簡潔,但是代碼的可閱讀性就會變的更差。
📒 覆寫基類中的equals
public class Student {public int ID;public String name;public Student(int Id,String name){this.ID = Id;//學號this.name=name;//姓名}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return ID == student.ID && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(ID, name);}@Overridepublic String toString() {return "Student{" +"ID=" + ID +", name='" + name + '\'' +'}';}} class priority{public static void main(String[] args) {Student student1 = new Student(1,"1號");Student student2 = new Student(1,"1號");System.out.println(student1.equals(student2));}}📖注意事項:
📖缺陷:
只能按照相等與否進行比較,不能按照大于或小于的方式進行比較
🔓 總結
1 利用JAVA源碼去分析,可以發現,對于非基本數據類型的對象的比較就是需要我們通過設定對應的比較方式去進行比較,這樣我們才可以進行比較
2 優先級隊列中是不能offer(null)的,這樣會拋出空異常!
3 對于Comparable接口,正如我們之前所學的那樣,擁有一個比較大的缺點,就是對類的侵入性強,如果我們改動類里面的比較方式,那么就可能會導致代碼出現異常。
4 對于Comparable,我們其實可以使用比較器Comparator去實現,從而可以減少對類的侵入性。
5 對于Comparator比較器而言,我們可以寫多個比較器,可以利用學號寫一個比較器,也可以利用姓名寫一個比較器。
總結
以上是生活随笔為你收集整理的从源码出发:JAVA中对象的比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 栈的基本应用
- 下一篇: 常见的排序算法(1)