網(wǎng)站建設衤金手指下拉10搜索引擎優(yōu)化的具體措施
一、問題提出
前面講了優(yōu)先級隊列,優(yōu)先級隊列在插入元素時有個要求:插入的元素不能是null或者元素之間必須要能夠進行比較,為了簡單起見,我們只是插入了Integer類型,
那優(yōu)先級隊列中能否插入自定義類型對象呢?
class Card{public int rank; // 數(shù)值public String suit; // 花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}
}
public class TestDome {public static void main(String[] args) {PriorityQueue<Card> priorityQueue = new PriorityQueue<>();priorityQueue.offer(new Card(5,"?"));priorityQueue.offer(null);System.out.println(priorityQueue);}
}
優(yōu)先級隊列底層使用堆,而向堆中插入元素時,為了滿足堆的性質(zhì),必須要進行元素的比較,而此時Card是沒有辦
法直接進行比較的,因此拋出異常。
通過實踐,我們發(fā)現(xiàn)在沒有指定 某種排序規(guī)則時,是無法將自定義類型入隊的。
至于 Comparable,可以參考這篇文章javaSE - 三個常用的接口(Comparable,Comparator,Cloneable)
回顧
關于 對象的比較來說:
1、equals 方法,比較的是對象,如果比較的兩個對象不相同:返回 false,反之,返回true
2、比較大小
我們的 Comparable 和 compareTo 使用比較大小的。指定比較的方式
我們要去堆Card 這種類型的對象進行比較,那就要實現(xiàn)Comparable或者Comparator,然后指定比較的方式,進行比較
Card 這個類里面有rank 和 suit 兩個屬性,是根據(jù)rank 或者 suit 進行比較
方法一、實現(xiàn)Comparable 接口
例如:使用rank 進行比較
方法一: 實現(xiàn)Comparable 接口 【注意!實現(xiàn)結結構,是要重寫接口內(nèi)部的抽象方法的】
class Card implements Comparable<Card>{public int rank; // 數(shù)值public String suit; // 花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}@Overridepublic int compareTo(Card o) {return this.rank - o.rank;}@Overridepublic String toString() {return "Card{" +"rank=" + rank +", suit='" + suit + '\'' +'}';}
}
public class TestDome {public static void main(String[] args) {PriorityQueue<Card> priorityQueue = new PriorityQueue<>();priorityQueue.offer(new Card(5,"?"));priorityQueue.offer(new Card(2,"?"));System.out.println(priorityQueue);}}
那么,問題來了。我們也沒有看見 優(yōu)先級隊列調(diào)用 compareTo 啊?
這里我們就需要去看一下,PriorityQueue 的 原碼。
既然,自定義類型的數(shù)據(jù)能放的進去,而且 其結果 是有序的。
那么,說明 offer 在添加 自定義元素時,肯定是比較了的。
所以,我們從 offer 入手。
方法二:創(chuàng)建一個比較器(類),用來實現(xiàn) Comparator 接口。通過這個類,來確定比較的規(guī)則
方法一對類的傾入性太強了,也就是說,在Card這個類里面實現(xiàn)比較的方式,那這個比較的方式就不能改了,但是如果哪天我們不根據(jù)rank進行比較,先要通過suit進行比較,那這個累計就不能實現(xiàn)比較了
所以我們應該將比較的方式單獨實現(xiàn)一個類,將不同的比較方式提出來,例如:
利用匿名內(nèi)部類實現(xiàn)上面的Comparator ,就是利用匿名內(nèi)部類試下比較器
使用 lambda 表達式 - 與上一種方法是等價的。
二、元素的比較
2.1、基本類型的比較
在Java中,基本類型的對象可以直接比較大小。
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println(a > b);
System.out.println(a < b);
System.out.println(a == b);
char c1 = 'A';
char c2 = 'B';
System.out.println(c1 > c2);
System.out.println(c1 < c2);
System.out.println(c1 == c2);
boolean b1 = true;
boolean b2 = false;
System.out.println(b1 == b2);
System.out.println(b1 != b2);
}
2.2、對象的比較
class Card {public int rank; // 數(shù)值public String suit; // 花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}
}
public class TestPriorityQueue {public static void main(String[] args) {Card c1 = new Card(1, "?");Card c2 = new Card(2, "?");Card c3 = c1;//System.out.println(c1 > c2); // 編譯報錯System.out.println(c1 == c2); // 編譯成功 ----> 打印false,因為c1和c2指向的是不同對象//System.out.println(c1 < c2); // 編譯報錯System.out.println(c1 == c3); // 編譯成功 ----> 打印true,因為c1和c3指向的是同一個對象}
}
c1、c2和c3分別是Card類型的引用變量,上述代碼在比較編譯時:
c1 > c2 編譯失敗
c1== c2 編譯成功
c1 < c2 編譯失敗
從編譯結果可以看出,Java中引用類型的變量不能直接按照 > 或者 < 方式進行比較。 那為什么可以比較?
因為:對于用戶實現(xiàn)自定義類型,都默認繼承自Object類,而Object類中提供了equal方法,而默認情況下調(diào)
用的就是equal方法,但是該方法的比較規(guī)則是:沒有比較引用變量引用對象的內(nèi)容,而是直接比較引用變量的地
址,但有些情況下該種比較就不符合題意。
我們也可以重寫equal方法:
class Card {public int rank; // 數(shù)值public String suit; // 花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}@Overridepublic String toString() {return "Card{" +"rank=" + rank +", suit='" + suit + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Card card = (Card) o;return rank == card.rank && Objects.equals(suit, card.suit);}@Overridepublic int hashCode() {return Objects.hash(rank, suit);}
}public class TestDome {public static void main(String[] args) {Card card1 = new Card(5,"?");Card card2 = new Card(5,"?");System.out.println(card1.equals(card2));}}
注意: 一般覆寫 equals 的套路就是上面演示的
- 如果指向同一個對象,返回 true
- 如果傳入的為 null,返回 false
- 如果傳入的對象類型不是 Card,返回 false
- 按照類的實現(xiàn)目標完成比較,例如這里只要花色和數(shù)值一樣,就認為是相同的牌
- 注意下調(diào)用其他引用類型的比較也需要 equals,例如這里的 suit 的比較
覆寫基類equal的方式雖然可以比較,但缺陷是:equal只能按照相等進行比較,不能按照大于、小于的方式進行
比較。