比較物件
| 導航 聚合 主題: |
在 Java 中,我們可以區分兩種型別的等式。
- 物件引用等式:當兩個物件引用指向同一個物件時。
- 物件值等式:當兩個獨立的物件恰好具有相同的數值/狀態時。
如果兩個物件在引用方面相等,它們在值方面也相等。
== 運算子可用於檢查兩個物件引用是否指向同一個物件。
程式碼部分 5.19:引用等式。
if (objRef1 == objRef2) {
// The two object references point to the same object
}
|
為了能夠比較同一個類的兩個 Java 物件, 方法必須被該類覆蓋並實現。boolean equals(Object obj)
實現者決定哪些值必須相等才能認為兩個物件相等。例如,在下面的類中,name 和 address 必須相等,但 description 不必。
程式碼清單 5.5:Customer.java
public class Customer {
private String name;
private String address;
private String description;
// ...
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (obj instanceof Customer cust) {
if ( ((cust.getName() == null && name == null) || cust.getName().equals(name))
&& ((cust.getAddress() == null && address == null) || cust.getAddress().equals(address))
) {
return true;
}
}
return false;
}
}
|
在 equals() 方法被覆蓋後,來自同一個類的兩個物件可以這樣比較
程式碼部分 5.20:方法用法。
Customer cust1 = new Customer();
Customer cust2 = new Customer();
//...
if (cust1.equals(cust2)) {
// Two Customers are equal, by name and address
}
|
注意,相等的物件必須具有相等的雜湊碼。因此,當覆蓋 equals 方法時,您也必須覆蓋 hashCode 方法。未能做到這一點將違反 hashCode 方法的一般約定,並且任何使用雜湊碼的類(例如 HashMap)將無法正常執行。
在 Java 中,有幾種現有的方法已經對來自任何類的物件進行了排序,例如 Collections.sort(List<T> list)。但是,Java 需要知道兩個物件之間的比較規則。因此,當您定義一個新類並希望您的類的物件可排序時,您必須實現 Comparable 並重新定義 compareTo(Object obj) 方法。
intcompareTo(T o)- 比較兩個物件並返回一個整數
- 負整數表示當前物件在自然排序中位於引數物件之前。
- 零表示當前物件和引數物件相等。
- 正整數表示當前物件在自然排序中位於引數物件之後。
假設名稱比地址更重要,而描述被忽略。
程式碼清單 5.6:SortableCustomer.java
public class SortableCustomer implements Comparable<SortableCustomer> {
private String name;
private String address;
private String description;
// ...
public int compareTo(SortableCustomer anotherCustomer) {
if (name.compareTo(anotherCustomer.getName()) == 0) {
return address.compareTo(anotherCustomer.getAddress());
} else {
return name.compareTo(anotherCustomer.getName());
}
}
}
|
實現此介面的物件可以用作排序地圖中的鍵或排序集中的元素,而無需指定比較器。
如果且僅當對於類 C 的每個 e1 和 e2,e1.compareTo((Object) e2) == 0 與 e1.equals((Object) e2) 具有相同的布林值,則類 C 的自然排序被認為與 equals 一致。注意,null 不是任何類的例項,並且 e.compareTo(null) 應該丟擲一個 NullPointerException,即使 e.equals(null) 返回 false。
強烈建議(但不是必需)自然排序與 equals 一致。這是因為沒有顯式比較器的排序集(和排序地圖)在與自然排序與 equals 不一致的元素(或鍵)一起使用時,行為“奇怪”。特別是,這樣的排序集(或排序地圖)違反了集合(或地圖)的一般約定,集合(或地圖)的一般約定是在 equals 方法的定義中定義的。
有時我們可能希望更改來自同一個類的物件集合的排序方式。我們可能希望按降序或升序排序。我們可能希望按name 或 address 排序。
我們需要為每種排序方式建立一個類。它必須實現 Comparator 介面。
從 Java 5.0 開始,Comparator 介面是泛型的;這意味著當您實現它時,您可以指定比較器可以比較的物件型別。
程式碼清單 5.7:CustomerComparator.java
public class CustomerComparator implements Comparator<Customer> {
public int compare(Customer cust1, Customer cust2) {
return cust1.getName().compareTo(cust2.getName());
}
}
|
上面的類然後可以與 SortedSet 或其他支援排序的集合關聯。
程式碼部分 5.21:比較器用法。
Collection<Customer> orderedCustomers = new TreeSet<Customer>(new CustomerComparator());
|
使用迭代器,可以按name 排序的順序遍歷 orderedCustomers 集合。
列表可以透過 Collections 的 sort 方法進行排序。
程式碼部分 5.22:自定義比較。
java.util.Collections.sort(custList, new CustomerComparator());
|
根據指定比較器引起的順序,對指定列表進行排序。列表中的所有元素都必須使用指定的比較器相互比較。
物件陣列也可以在 Comparator 的幫助下進行排序。
程式碼部分 5.23:陣列排序。
SortableCustomer[] customerArray;
//...
java.util.Arrays.sort(customerArray, new CustomerComparator());
|
根據指定比較器引起的順序,對指定的 Customer 物件陣列(customerArray)進行排序。陣列中的所有元素都必須使用指定的比較器相互比較。
