<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本篇部落格主要內容:
優先順序佇列在插入元素時有個要求:插入的元素不能是null或者元素之間必須要能夠 進行比較,為了簡單起見,我們只是插入了Integer型別,那優先順序佇列中能否插入自定義型別物件呢?
class Card { public int rank; // 數值 public String suit; // 花色 public Card(int rank, String suit) { this.rank = rank; this.suit = suit; } } public class TestPriorityQueue { public static void TestPriorityQueue() { PriorityQueue<Card> p = new PriorityQueue<>(); p.offer(new Card(1, "♠")); p.offer(new Card(2, "♠")); } public static void main(String[] args) { TestPriorityQueue(); } }
優先順序佇列底層使用堆,而向堆中插入元素時,為了滿足堆的性質,必須要進行元素的比較,而此時Card是沒有辦法直接進行比較的,因此丟擲異常。
在Java中,基本型別的物件可以直接比較大小。
public class TestCompare { 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); } }
class Card { public int rank; // 數值 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型別的參照變數,上述程式碼在比較編譯時:
從編譯結果可以看出, Java中參照型別的變數不能直接按照 > 或者 < 方式進行比較。 那為什麼‘==‘可以比較?
因為: 對於使用者實現自定義型別,都預設繼承自Object類,而Object類中提供了equal方法,而==預設情況下呼叫的就是equal方法,但是該方法的比較規則是: 沒有比較參照變數參照物件的內容,而是直接比較參照變數的地 址 ,但有些情況下該種比較就不符合題意。
比較參照型別的關係:
以撲克牌的數值和花色為例子:
比較:
//數值比較器 class RankComparator implements Comparator<Card>{ @Override public int compare(Card o1, Card o2) { return o1.rank-o2.rank; } } //花色比較器 class SuitComparator implements Comparator<Card>{ @Override public int compare(Card o1, Card o2) { return o1.suit.compareTo(o2.suit); } } public class Test01 { public static void main(String[] args) { //數值比較器 RankComparator rankComparator=new RankComparator(); Card card1=new Card(1,"♠"); Card card2=new Card(2,"♣"); rankComparator.compare(card1,card2); //花色比較器 SuitComparator suitComparator=new SuitComparator(); System.out.println(suitComparator.compare(card1,card2)); } }
// Object中equal的實現 ,可以看到:直接比較的是兩個參照變數的地址 public boolean equals(Object obj) { return (this == obj); }
判斷相等:
class Card implements Comparable<Card>{ public int rank; // 數值 public String suit; // 花色 public Card(int rank, String suit) { this.rank = rank; this.suit = suit; } public Card() { super(); } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { if(this==obj)return true; if(obj==null || getClass()!=obj.getClass())return false; Card card=(Card)obj; return rank== card.rank && Objects.equals(suit,card.suit); } @Override public int compareTo(Card o) { return this.rank-o.rank; } } public class Test01 { public static void main(String[] args) { Card card1=new Card(1,"♠"); Card card2=new Card(2,"♠"); System.out.println(card1==card2);//判斷兩張牌的地址是否相等 System.out.println(card1.equals(card2));//判斷兩張牌是否相等 System.out.println(card1.compareTo(card2));//比較兩張牌 } }
public class Card { public int rank; // 數值 public String suit; // 花色 public Card(int rank, String suit) { this.rank = rank; this.suit = suit; } @Override public boolean equals(Object o) { // 自己和自己比較 if (this == o) { return true; } // o如果是null物件 ,或者o不是Card的子類 if (o == null | | !(o instanceof Card)) { return false; } // 注意基本型別可以直接比較 ,但參照型別最好呼叫其equal方法 Card c = (Card)o; return rank == c.rank && suit.equals(c.suit); } }
注意: 一般覆寫 equals 的套路就是上面演示的
1、如果指向同一個物件,返回 true
2、如果傳入的為 null,返回 false
3、 如果傳入的物件型別不是 Card,返回 false
4、 按照類的實現目標完成比較,例如這裡只要花色和數值一樣,就認為是相同的牌
5、注意下呼叫其他參照型別的比較也需要 equals,例如這裡的 suit 的比較
覆寫基礎類別equal的方式雖然可以比較,但缺陷是: equal只能按照相等進行比較,不能按照大於、小於的方式進行 比較。
Comparble是JDK提供的泛型的比較介面類,原始碼實現具體如下:
public interface Comparable<E> { // 返回值: // < 0: 表示 this 指向的物件小於 o 指向的物件 // == 0: 表示 this 指向的物件等於 o 指向的物件 // > 0: 表示 this 指向的物件大於 o 指向的物件 int compareTo(E o); }
對於使用者自定義型別,如果要想按照大小與方式進行比較時: 在定義類時,實現Comparble介面即可,然後在類 中重寫compareTo方法。
public class Card implements Comparable<Card> { public int rank; // 數值 public String suit; // 花色 public Card(int rank, String suit) { this.rank = rank; this.suit = suit; } // 根據數值比較 ,不管花色 // 這裡我們認為 null 是最小的 @Override public int compareTo(Card o) { if (o == null) { return 1; } return rank - o.rank; } public static void main(String[] args){ Card p = new Card(1, "♠"); Card q = new Card(2, "♠"); Card o = new Card(1, "♠"); System.out.println(p.compareTo(o)); // == 0 ,表示牌相等 System.out.println(p.compareTo(q)); // < 0 ,表示 p 比較小 System.out.println(q.compareTo(p)); // > 0 ,表示 q 比較大 } }
Compareble是java.lang中的介面類,可以直接使用。
按照比較器方式進行比較,具體步驟如下:
使用者自定義比較器類,實現Comparator介面
public interface Comparator<T> { // 返回值: // < 0: 表示 o1 指向的物件小於 o2 指向的物件 // == 0: 表示 o1 指向的物件等於 o2 指向的物件 // > 0: 表示 o1 指向的物件等於 o2 指向的物件 int compare(T o1, T o2); }
注意:
區分Comparable和Comparator。
import java.util.Comparator; class Card { public int rank; // 數值 public String suit; // 花色 public Card(int rank, String suit) { this.rank = rank; this.suit = suit; } } class CardComparator implements Comparator<Card> { // 根據數值比較 ,不管花色 // 這裡我們認為 null 是最小的 @Override public int compare(Card o1, Card o2) { if (o1 == o2) { return 0; } if (o1 == null) { return -1; } if (o2 == null) { return 1; } return o1.rank - o2.rank; } public static void main(String[] args){ Card p = new Card(1, "♠"); Card q = new Card(2, "♠"); Card o = new Card(1, "♠"); // 定義比較器物件 CardComparator cmptor = new CardComparator(); // 使用比較器物件進行比較 System.out.println(cmptor.compare(p, o)); System.out.println(cmptor.compare(p, q)); System.out.println(cmptor.compare(q, p)); } }
覆寫的方法 | 說明 |
---|---|
Object.equals | 因為所有類都是繼承自 Object 的,所以直接覆寫即可,不過只能比較相等與 否 |
Comparable.compareTo | 需要手動實現介面,侵入性比較強,但一旦實現,每次用該類都有順序,屬於內部順序 |
Comparator.compare | 需要實現一個比較器物件,對待比較類的侵入性弱,但對演演算法程式碼實現侵入性強 |
集合框架中的PriorityQueue底層使用堆結構,因此其內部的元素必須要能夠比大小, PriorityQueue採用了: Comparble和Comparator兩種方式。
1.Comparble是預設的內部比較方式,如果使用者插入自定義型別物件時,該類物件必須要實現Comparble接 口,並覆寫compareTo方法
2.使用者也可以選擇使用比較器物件,如果使用者插入自定義型別物件時,必須要提供一個比較器類,讓該類實現 Comparator介面並覆寫compare方法。
// JDK中PriorityQueue的實現: public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable { // ... // 預設容量 private static final int DEFAULT_INITIAL_CAPACITY = 11; // 內部定義的比較器物件 ,用來接收使用者範例化PriorityQueue物件時提供的比較器物件 private final Comparator<? super E> comparator; // 使用者如果沒有提供比較器物件 ,使用預設的內部比較 ,將comparator置為null public PriorityQueue() { this(DEFAULT_INITIAL_CAPACITY, null); } // 如果使用者提供了比較器 ,採用使用者提供的比較器進行比較 public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility if (initialCapacity < 1) throw new IllegalArgumentException(); this.queue = new Object[initialCapacity]; this.comparator = comparator; } // ... // 向上調整: // 如果使用者沒有提供比較器物件 ,採用Comparable進行比較 // 否則使用使用者提供的比較器物件進行比較 private void siftUp(int k, E x) { if (comparator != null) siftUpUsingComparator(k, x); else siftUpComparable(k, x); } // 使用Comparable @SuppressWarnings("unchecked") private void siftUpComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>) x; while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (key.compareTo((E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = key; } // 使用使用者提供的比較器物件進行比較 @SuppressWarnings("unchecked") private void siftUpUsingComparator(int k, E x) { while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (comparator.compare(x, (E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = x; } }
到此這篇關於Java資料結構之物件比較詳解的文章就介紹到這了,更多相關Java物件比較內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45