一個 List l 可能被做如下排序:
Collections.sort(l);
假如這個 list 由 String 元素所組成, 那么它將按詞典排序法(按字母順序)進行排序; 假如它是由 Date 元素所組成, 那么它將按年代順序來排序。 java 怎么會知道該怎么做呢? 這一定是個魔術! 其實不然。實際上, String 和 Date 均實現了Comparable接口。 Comparable 接口為一個類提供一個 自然排序( natural ordering), 它答應那個類的對象被自動排序。下表列出了實現了Comparable 的JDK類:
類 自然排序
Byte 帶符號的數字排序
Character 不帶符號的數字排序
Long 帶符號的數字排序
Integer 帶符號的數字排序
Short 帶符號的數字排序
Double 帶符號的數字排序
Float 帶符號的數字排序
BigInteger 帶符號的數字排序
BigDecimal 帶符號的數字排序
File 依靠系統的按路徑名字母順序排序
String 按字母順序排序
Date 按年代順序排序
CollationKey 特定字符集按字母順序排序
假如你要為一個其元素沒有實現 Comparable的列表排序,Collections.sort(list) 將扔出一個 ClassCastException。類似的,假如你要為一個其元素沒有作相互比較的列表進行排序, Collections.sort 將扔出一個 ClassCastException. 能夠被相互比較的元素被稱作 mutually comparable(可相互比較的)。 雖然不同類型的元素有可能被相互比較,但以上列出的任何JDK類型都不答應在類之間的比較 (inter-class comparison)。
假如你只是要為可比較的元素的列表進行排序,或為它們創建排序的對象集, 則這就是你實際需要了解的全部有關 Comparable 接口的內容。假如你要實現你自己的 Comparable 類型,則下一節將會引起你的愛好。
編寫你自己的 Comparable 類型
Comparable 接口由一個單一的方法構成:
public interface Comparable {
public int compareTo(Object o);
}
compareTo 方法將接收對象與特定對象進行比較,并在接收對象小于、等于或大于特定對象時分別返回負整數、空或一個正整數。假如特定對象不能與接收對象相比較,該方法扔出一個ClassCastException. 這是一個表示某人姓名的類(a class rePResenting a person´s name), 它實現了 Comparable:
import java.util.*;
public class Name implements Comparable {
private String firstName, lastName;
public Name(String firstName, String lastName) {if (firstName==null lastName==null)
throw new NullPointerException();
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() {return firstName;}
public String lastName() {return lastName;}
public boolean equals(Object o) {
if (!(o instanceof Name))
return false;
Name n = (Name)o;return n.firstName.equals(firstName) &&n.lastName.equals(lastName);
}
public int hashCode() {
return 31*firstName.hashCode() + lastName.hashCode();
}
public String toString() {return firstName + " " + lastName;}
public int compareTo(Object o) {Name n = (Name)o;
int lastCmp = lastName.compareTo(n.lastName);
return (lastCmp!=0 ? lastCmp :
firstName.compareTo(n.firstName));
}}
為了使這個例子短一些,該類受到了一點限制:它不支持中間名,它要求必須同時具有first name 和 last name, 而這不是在全世界都通用的。盡管如此,這個例子仍有幾個重要之處:
Name 對象是不變的( immutable)。作為相等、不變類型的所有其它事情就是如何做的問題,非凡是對那些將被用來作為 Sets 中的元素或 Maps 中的鍵的對象來說,更是如此。假如你對這些 對象集 中的元素或鍵做了更改,這些 對象集 將中斷。
構造函數可檢查它的參數是否為 null。 這可以保證所有的Name 對象都能很好地形成。因而沒有其它方法會扔出NullPointerException.
hashCode 方法被重新定義。對重新定義 equals 方法的任意類來說,這是必需的(essential)。 一般約定(general contract)需要 Object.equals. (Equal 對象必須具有相等的哈希代碼) 。
假如特定對象為 null,或一個不適當的類型, equals 方法則返回 false。 在這種情況下, compareTo 方法扔出一個運行時異常。這兩個行為都是各自方法的一般約定所必需的。
toString 方法已被重新定義,從而可以以人們能夠讀懂的形式打印 Name 。這總是一個好主意,非凡是對要被放入對象集 中的對象來說,更有益處。各種 對象集 類型的 toString 方法依靠它們的元素、鍵和值的 toString 方法。
由于這一節介紹的是有關元素排序的問題,因而讓我們稍微多談一點 Name 的 compareTo 方法。它實現標準的姓名-排序算法,在該算法中,last name 優先于 first name。這恰恰是你在一個natural ordering(自然排序)中所想要的。 假如自然排序不自然,那才輕易引起混亂呢!
請看 compareTo 是如何被實現的,因為它是相當典型的。首先,你將 Object 參數轉換為適當類型; 假如參數類型是不適當的,則會扔出一個適當的異常(ClassCastException);那么你應該比較對象的最重要部分(在此案例中為 last name)。通常,你可以使用該部分的類型的自然排序。 在次案例中,該部分是一個 String, 并且自然的(按詞典順序的)排序正是所要求的。假如比較的結果是空(它表示等同性)之外的其它東西,你就做完了:你可以返回結果。 假如最重要的部分是相等的,你就應該繼續比較次重要部分。在此案例中,只有兩個部分 (first name and last name)。 假如有更多的部分,你就應該以顯而易見的方式繼續進行,直到發現兩個不相等的部分(否則你就應該比較最不重要的部分),這時,你就可以返回比較結果了。 這是 一個建立 Name 對象列表并對它們進行排序的小程序:
新聞熱點
疑難解答