首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Comparator 介面契約義務完整解析

     編輯:Java 相關知識

前言

java.util.Comparator 介面雖簡單(僅需實作 compare(Object o1, Object o2)),但其 API 文件規定的契約義務常被忽略,導致排序行為異常或序列化失敗。本文詳細解析三大核心契約。

契約一:對稱性

  • compare(a, b) 與 compare(b, a) 結果必須相反:一正一負,或皆為零
  • 數值大小可不同(如 4 vs -2 合法),但正負號必須相反
  • 拋出例外也必須對稱:compare(a, b) 拋 ClassCastException,則 compare(b, a) 也必須拋同類型例外

違反範例

public int compare(Object o1, Object o2) {
  if (o1 instanceof Long) {
    Long ln = (Long) o1;
    return ln.compareTo(o2); // o2 非 Long 時拋 ClassCastException
  }
  return 0;
}

a = new Long(5), b = "Text" 時:compare(a, b) 拋例外,compare(b, a) 回傳 0 —— 違反對稱性。

契約二:可序列化

TreeSet、TreeMap 儲存 Comparator 以維持排序,若集合需序列化,Comparator 必須實作 Serializable。否則序列化集合時會拋 NotSerializableException。

契約三:實作 equals 方法

當 Comparator 有多種比較模式(如依名稱、依年齡、依薪資排序)時,應覆寫 equals(Object obj),讓集合能正確判斷兩個 Comparator 是否相等(影響 TreeSet/TreeMap 合併、比較邏輯)。

多模式 Comparator 範例

public class ExampleComparator implements Comparator, Serializable {
  private int type; // 1: 依名稱, 2: 依年齡
  public ExampleComparator(int type) { this.type = type; }

  public int compare(Object o1, Object o2) {
    if (type == 1) { /* 依名稱比較 */ }
    else if (type == 2) { /* 依年齡比較 */ }
    return 0;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof ExampleComparator)) return false;
    ExampleComparator other = (ExampleComparator) obj;
    return this.type == other.type;
  }
}

總結檢查清單

  1. compare 回傳值正負對稱,例外拋擲對稱
  2. 實作 Serializable(若用於可序列化集合)
  3. 多比較模式時覆寫 equals(含 hashCode 最佳實務)

結語

Comparator 看似簡單,但契約義務關係到排序正確性、集合序列化與邏輯一致性。實作時務必閱讀 API 文件並遵守三大契約,避免難以除錯的潛在缺陷。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved