<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    yxhxj2006

    常用鏈接

    統計

    最新評論

    Java 集合框架

    在常見用法中,集合(collection)和數學上直觀的集(set)的概念是相同的。 集是一個唯一項組,也就是說組中沒有重復項。實際上,“集合框架”包含了一個 Set 接口和許多具體的 Set 類。但正式的集概念卻比 Java 技術提前了一個世紀,那時英國數學家 George Boole 按邏輯正式的定義了集的概念。大部分人在小學時通過我們熟悉的維恩圖引入的“集的交”和“集的并”學到過一些集的理論。 

    集的一些現實的示例如下: 
    •大寫字母集“A”到“Z” 
    •非負整數集{0, 1, 2 ...} 
    •保留的 Java 編程語言關鍵字集 {'import', 'class', 'public', 'protected'...} 
    •人集(friends, employees, clients, ...) 
    •數據庫查詢返回記錄集 
    •Container 的 Component 對象集 
    •所有對(pair)集 
    •空集{} 

    集的基本屬性如下: 
    •集內只包含每項的一個實例 
    •集可以是有限的,也可以是無限的 
    •可以定義抽象概念 

    集不僅是邏輯學、數學和計算機科學的基礎,對于商業和系統的日常應用來說,它也很實用。“連接池”這一概念就是數據庫服務器的一個開放連接集。Web 服務器必須管理客戶機和連接集。文件描述符提供了操作系統中另一個集的示例。 

    映射是一種特別的集。它是一種對(pair)集,每個對表示一個元素到另一元素的單向映射。一些映射示例有: 
    •IP 地址到域名(DNS)的映射 
    •關鍵字到數據庫記錄的映射 
    •字典(詞到含義的映射) 
    •2 進制到 10 進制轉換的映射 

    就像集一樣,映射背后的思想比 Java 編程語言早的多,甚至比計算機科學還早。集和映射是數學領域的重要工具,人們非常了解它們的屬性。不僅如此,人們早就認識到用集和映射解決編程問題是有效的。1969 年發明的一種名為 SETL(Set Language)的語言只包含 set 一種基本數據類型(SETL 也包含垃圾收集 ― 這項技術在 20 世紀 90 年代開發了 Java 技術后才被人們普遍接受)。雖然連 C++ 在內的許多語言都包含集和映射,但“集合框架”很可能是設計最完美的集和映射包,并且是為流行的語言而寫的。 (C++ 標準模板庫(Standard Template Library(STL))和 Smalltalk 的集合層次結構的用戶對最后一點可能有爭議。) 

    此外,因為映射也是集,所以它們可以是有限的,也可以是無限的。 無限映射的一個示例如 2 進制到 10 進制的轉換。不幸的是,“集合框架”不支持無限映射 ― 有時用數學函數、公式或算法更好。但在有限映射能解決問題時,“集合框架”會給 Java 程序員提供一個有用的 API。 

    因為“集合框架”有類 Set、Collection 和 Map 的正規定義,您會注意到小寫的詞 set、collection 和 map 把實現和概念區分開來。 

    集合接口和類 

    既然您已經具備了一些集的理論,您應該能夠更輕松的理解“集合框架”。 “集合框架”由一組用來操作對象的接口組成。不同接口描述不同類型的組。 在很大程度上,一旦您理解了接口,您就理解了框架。 雖然您總要創建接口特定的實現,但訪問實際集合的方法應該限制在接口方法的使用上;因此,允許您更改基本的數據結構而不必改變其它代碼。框架接口層次結構如下圖所示。 

    有的人可能會認為 Map 會繼承 Collection。 在數學中,映射只是對(pair)的集合。但是,在“集合框架”中,接口 Map 和 Collection 在層次結構沒有任何親緣關系,它們是截然不同的。這種差別的原因與 Set 和 Map 在 Java 庫中使用的方法有關。Map 的典型應用是訪問按關鍵字存儲的值。它支持一系列集合操作的全部,但操作的是鍵-值對,而不是單個獨立的元素。因此 Map 需要支持 get() 和 put() 的基本操作,而 Set 不需要。此外,還有返回 Map 對象的 Set 視圖的方法: 
    Set set = aMap.keySet(); 
    用“集合框架”設計軟件時,記住該框架四個基本接口的下列層次結構關系會有用處: 
    •Collection 接口是一組允許重復的對象。 
    •Set 接口繼承 Collection,但不允許重復。 
    •List 接口繼承 Collection,允許重復,并引入位置下標。 
    •Map 接口既不繼承 Set 也不繼承 Collection。 

    讓我們轉到對框架實現的研究,具體的集合類遵循命名約定,并將基本數據結構和框架接口相結合。除了四個歷史集合類外,Java 2 框架還引入了六個集合實現,如下表所示。關于歷史集合類如何轉換、比如說,如何修改 Hashtable并結合到框架中,請參閱歷史集合類 。 

    接口 實現 歷史集合類 
    Set HashSet 
    TreeSet 
    List ArrayList Vector 
    LinkedList Stack 
    Map HashMap Hashtable 
    TreeMap Properties 

    這里沒有 Collection 接口的實現。歷史集合類,之所以這樣命名是因為從 Java 類庫 1.0 發行版就開始沿用至今了。 

    如果從歷史集合類轉換到新的框架類,主要差異之一在于所有的操作都和新類不同步。您可以往新類中添加同步的實現,但您不能把它從舊的類中除去。 


    -------------------------------------------------------------------------------- 


    集合接口 

    Collection 接口用于表示任何對象或元素組。想要盡可能以常規方式處理一組元素時,就使用這一接口。這里是以統一建模語言(Unified Modeling Language(UML))表示法表示的 Collection 公有方法清單。 

    該接口支持如添加和除去等基本操作。設法除去一個元素時,如果這個元素存在,除去的僅僅是集合中此元素的一個實例。 
    •boolean add(Object element) 
    •boolean remove(Object element) 

    Collection 接口還支持查詢操作: 
    •int size() 
    •boolean isEmpty() 
    •boolean contains(Object element) 
    •Iterator iterator() 

    Iterator 接口 

    Collection 接口的 iterator() 方法返回一個 Iterator。Iterator 和您可能已經熟悉的 Enumeration接口類似,我們將在Enumeration 接口中對 Enumeration 進行討論。使用 Iterator 接口方法,您可以從頭至尾遍歷集合,并安全的從底層 Collection 中除去元素: 

    remove() 方法可由底層集合有選擇的支持。當底層集合調用并支持該方法時,最近一次 next() 調用返回的元素就被除去。為演示這一點,用于常規 Collection 的 Iterator 接口代碼如下: 
    Collection collection = ...; 
    Iterator iterator = collection.iterator(); 
    while (iterator.hasNext()) { 
    Object element = iterator.next(); 
    if (removalCheck(element)) { 
    iterator.remove(); 



    組操作 

    Collection 接口支持的其它操作,要么是作用于元素組的任務,要么是同時作用于整個集合的任務。 
    •boolean containsAll(Collection collection) 
    •boolean addAll(Collection collection) 
    •void clear() 
    •void removeAll(Collection collection) 
    •void retainAll(Collection collection) 

    containsAll() 方法允許您查找當前集合是否包含了另一個集合的所有元素,即另一個集合是否是當前集合的子集。其余方法是可選的,因為特定的集合可能不支持集合更改。addAll() 方法確保另一個集合中的所有元素都被添加到當前的集合中,通常稱為并。clear() 方法從當前集合中除去所有元素。removeAll() 方法類似于 clear(),但只除去了元素的一個子集。retainAll() 方法類似于 removeAll() 方法,不過可能感到它所做的與前面正好相反:它從當前集合中除去不屬于另一個集合的元素,即交。 

    剩下的兩種將 Collection轉換成數組的接口方法,將在新集合到歷史集合的轉換中討論。 

    AbstractCollection 類 

    AbstractCollection 類提供具體“集合框架”類的基本功能。雖然您可以自行實現 Collection 接口的所有方法,但是,除了iterator() 和 size() 方法在恰當的子類中實現以外,其它所有方法都由 AbstractCollection 類來提供實現。如果子類不覆蓋某些方法,可選的如 add() 之類的方法將拋出異常。 

    “集合框架”設計的相關事項 

    在創建“集合框架”的過程中,我們需要 Sun 開發小組提供用于操作元素組的靈活接口。 為了使設計簡單,我們不為每個可選的功能分別提供獨立的接口,而是提供了一個定義所有方法的接口。而這些方法是一個實現類才有可能提供的。然而,有些接口方法是可選的。因為一個接口實現必須實現所有接口方法,調用程序就需要一種途徑來知道一個可選的方法是不是不受支持。調用一種可選方法時,框架開發小組所選擇去通知調用程序的方式是拋出一個 UnsupportedOperationException。 如果在使用集合的過程中,一個 UnsupportedOperationException 被拋出,則操作失敗,因為它不受支持。UnsupportedOperationException 類繼承 RuntimeException 類避免了不得不把所有集合操作放入 try-catch 塊。 

    除了借助運行時異常處理可選操作外,具體集合實現的迭代器還是 故障快速(fail-fast)的。這意味著,當另一個線程修改底層集合的時候,如果您正在用 Iterator 遍歷集合,那么,Iterator就會拋出 ConcurrentModificationException (另一種 RuntimeException)異常立刻失敗。就是說,下次調用 Iterator 方法時底層集合已修改過了,ConcurrentModificationException 異常就拋出了。 

    -------------------------------------------------------------------------------- 

    Set 接口 

    按照定義,Set 接口繼承 Collection 接口,而且它不允許集合中存在重復項。所有原始方法都是現成的,沒有引入新方法。具體的 Set 實現類依賴添加的對象的 equals() 方法來檢查等同性。 

    HashSet 類和 TreeSet 類 

    “集合框架”支持 Set 接口兩種普通的實現:HashSet 和 TreeSet。在更多情況下,您會使用 HashSet 存儲重復自由的集合。考慮到效率,添加到 HashSet 的對象需要采用恰當分配散列碼的方式來實現 hashCode() 方法。雖然大多數系統類覆蓋了 Object 中缺省的 hashCode() 實現,但創建您自己的要添加到 HashSet 的類時,別忘了覆蓋 hashCode()。當您要從集合中以有序的方式抽取元素時,TreeSet 實現會有用處。為了能順利進行,添加到 TreeSet 的元素必須是可排序的。 “集合框架”添加對 Comparable元素的支持,在排序的“可比較的接口”部分中會詳細介紹。我們暫且假定一棵樹知道如何保持 java.lang 包裝程序器類元素的有序狀態。一般說來,先把元素添加到 HashSet,再把集合轉換為 TreeSet 來進行有序遍歷會更快。 

    為優化 HashSet 空間的使用,您可以調優初始容量和負載因子。TreeSet 不包含調優選項,因為樹總是平衡的,保證了插入、刪除、查詢的性能為 log(n)。 

    HashSet 和 TreeSet 都實現 Cloneable 接口。 

    集的使用示例 

    為演示具體 Set 類的使用,下面的程序創建了一個 HashSet,并往里添加了一組名字,其中有個名字添加了兩次。接著,程序把集中名字的列表打印出來,演示了重復的名字沒有出現。 接著,程序把集作為 TreeSet 來處理,并顯示有序的列表。 
    import java.util.*; 

    public class SetExample { 
    public static void main(String args[]) { 
    Set set = new HashSet(); 
    set.add("Bernadine"); 
    set.add("Elizabeth"); 
    set.add("Gene"); 
    set.add("Elizabeth"); 
    set.add("Clara"); 
    System.out.println(set); 
    Set sortedSet = new TreeSet(set); 
    System.out.println(sortedSet); 


    運行程序產生了以下輸出。請注意重復的條目只出現了一次,列表的第二次輸出已按字母順序排序。 
    [Gene, Clara, Bernadine, Elizabeth] 
    [Bernadine, Clara, Elizabeth, Gene] 

    AbstractSet 類 

    AbstractSet 類覆蓋了 equals() 和 hashCode() 方法,以確保兩個相等的集返回相同的散列碼。若兩個集大小相等且包含相同元素,則這兩個集相等。 按定義,集散列碼是集中元素散列碼的總和。 因此,不論集的內部順序如何,兩個相等的集會報告相同的散列碼。 


    -------------------------------------------------------------------------------- 


    練系 
    •練習 1. 如何將 HashSet 用于一個稀疏的位集 
    •練習 2. 如何使用 TreeSet 提供有序的 JList 


    -------------------------------------------------------------------------------- 


    List 接口 

    List 接口繼承了 Collection 接口以定義一個允許重復項的有序集合。 該接口不但能夠對列表的一部分進行處理,還添加了面向位置的操作。 

    面向位置的操作包括插入某個元素或 Collection 的功能,還包括獲取、除去或更改元素的功能。 在 List 中搜索元素可以從列表的頭部或尾部開始,如果找到元素,還將報告元素所在的位置。 
    •void add(int index, Object element) 
    •boolean addAll(int index, Collection collection) 
    •Object get(int index) 
    •int indexOf(Object element) 
    •int lastIndexOf(Object element) 
    •Object remove(int index) 
    •Object set(int index, Object element) 

    List 接口不但以位置友好的方式遍歷整個列表,還能處理集合的子集: 
    •ListIterator listIterator() 
    •ListIterator listIterator(int startIndex) 
    •List subList(int fromIndex, int toIndex) 

    處理 subList() 時,位于 fromIndex 的元素在子列表中,而位于 toIndex 的元素則不是,提醒這一點很重要。以下 for-loop 測試案例大致反映了這一點: 
    for (int i=fromIndex; i<toIndex; i++) { >
    // process element at position i 

    此外,我們還應該提醒的是 ― 對子列表的更改(如 add()、remove() 和 set() 調用)對底層 List 也有影響。 

    ListIterator 接口 

    ListIterator 接口繼承 Iterator 接口以支持添加或更改底層集合中的元素,還支持雙向訪問。 

    以下源代碼演示了列表中的反向循環。請注意 ListIterator 最初位于列表尾之后(list.size()),因為第一個元素的下標是 0。 
    List list = ...; 
    ListIterator iterator = list.listIterator(list.size()); 
    while (iterator.hasPrevious()) { 
    Object element = iterator.previous(); 
    // Process element 

    正常情況下,不用 ListIterator 改變某次遍歷集合元素的方向 ― 向前或者向后。 雖然在技術上可能實現時,但在 previous() 后立刻調用 next(),返回的是同一個元素。把調用 next() 和 previous() 的順序顛倒一下,結果相同。 

    我們還需要稍微再解釋一下 add() 操作。添加一個元素會導致新元素立刻被添加到隱式光標的前面。因此,添加元素后調用 previous() 會返回新元素,而調用 next() 則不起作用,返回添加操作之前的下一個元素。 

    ArrayList 類和 LinkedList 類 

    在“集合框架”中有兩種常規的 List 實現:ArrayList 和 LinkedList。 使用兩種 List 實現的哪一種取決于您特定的需要。如果要支持隨機訪問,而不必在除尾部的任何位置插入或除去元素, 那么,ArrayList 提供了可選的集合。 但如果,您要頻繁的從列表的中間位置添加和除去元素,而只要順序的訪問列表元素,那么,LinkedList 實現更好。 

    ArrayList 和 LinkedList 都實現 Cloneable 接口。此外,LinkedList 添加了一些處理列表兩端元素的方法(下圖只顯示了新方法): 

    使用這些新方法,您就可以輕松的把 LinkedList 當作一個堆棧、隊列或其它面向端點的數據結構。 
    LinkedList queue = ...; 
    queue.addFirst(element); 
    Object object = queue.removeLast();LinkedList stack = ...; 
    stack.addFirst(element); 
    Object object = stack.removeFirst(); 
    Vector 類和 Stack 類是 List接口的歷史實現。我們將在Vector 類和 Stack 類中討論它們。 

    List 的使用示例 

    下面的程序演示了具體 List 類的使用。第一部分,創建一個由 ArrayList 支持的 List。填充完列表以后,特定條目就得到了。示例的 LinkedList 部分把 LinkedList 當作一個隊列,從隊列頭部添加東西,從尾部除去。 
    import java.util.*; 

    public class ListExample { 
    public static void main(String args[]) { 
    List list = new ArrayList(); 
    list.add("Bernadine"); 
    list.add("Elizabeth"); 
    list.add("Gene"); 
    list.add("Elizabeth"); 
    list.add("Clara"); 
    System.out.println(list); 
    System.out.println("2: " + list.get(2)); 
    System.out.println("0: " + list.get(0)); 
    LinkedList queue = new LinkedList(); 
    queue.addFirst("Bernadine"); 
    queue.addFirst("Elizabeth"); 
    queue.addFirst("Gene"); 
    queue.addFirst("Elizabeth"); 
    queue.addFirst("Clara"); 
    System.out.println(queue); 
    queue.removeLast(); 
    queue.removeLast(); 
    System.out.println(queue); 


    運行程序產生了以下輸出。請注意,與 Set 不同的是 List 允許重復。 
    [Bernadine, Elizabeth, Gene, Elizabeth, Clara] 
    2: Gene 
    0: Bernadine 
    [Clara, Elizabeth, Gene, Elizabeth, Bernadine] 
    [Clara, Elizabeth, Gene] 
    AbstractList 類和 AbstractSequentialList 類 

    有兩個抽象的 List 實現類:AbstractList 和 AbstractSequentialList。像 AbstractSet 類一樣,它們覆蓋了 equals() 和 hashCode() 方法以確保兩個相等的集合返回相同的散列碼。若兩個集大小相等且包含順序相同的相同元素,則這兩個集相等。 這里的 hashCode() 實現在 List 接口定義中指定,而在這里實現。 

    除了 equals() 和 hashCode() 實現,AbstractList 和 AbstractSequentialList 實現了其余 List 方法的一部分。因為數據源隨機訪問和順序訪問是分別實現的,使得具體列表實現的創建更為容易。需要定義的一套方法取決于您希望支持的行為。下表應該能夠幫您記住需要實現哪些方法。 您永遠不必親自提供的是 Iterator iterator() 方法的實現。 

    AbstractList AbstractSequentialList 


    不可修改 Object get(int index) ListIterator listIterator(int index) 
    int size() - boolean hasNext() 
    - Object next() 
    - int nextIndex() 
    - boolean hasPrevious() 
    - Object previous() 
    - int previousIndex() 
    int size() 


    可修改 Object get(int index) ListIterator listIterator(int index) 
    int size() - boolean hasNext() 
    Object set(int index, Object element) - Object next() 
    - int nextIndex() 
    - boolean hasPrevious() 
    - Object previous() 
    - int previousIndex() 
    int size() 
    ListIterator 
    - set(Object element) 

    變量大小和可修改性 Object get(int index) ListIterator listIterator(int index) 
    int size() - boolean hasNext() 
    Object set(int index, Object element) - Object next() 
    add(int index, Object element) - int nextIndex() 
    Object remove(int index) - boolean hasPrevious() 
    - Object previous() 
    - int previousIndex() 
    int size() 
    ListIterator 
    - set(Object element) 
    ListIterator 
    - add(Object element) 
    - remove() 

    正如 Collection 接口文檔所述,您還應該提供兩個構造函數,一個無參數,一個接受另一個 Collection。 

    -------------------------------------------------------------------------------- 

    練習 
    •練習 3. 如何用 JComboBox 實現 ArrayList 

    -------------------------------------------------------------------------------- 

    Map 接口 

    Map 接口不是 Collection 接口的繼承。而是從自己的用于維護鍵-值關聯的接口層次結構入手。按定義,該接口描述了從不重復的鍵到值的映射。 

    我們可以把這個接口方法分成三組操作:改變、查詢和提供可選視圖。 

    改變操作允許您從映射中添加和除去鍵-值對。鍵和值都可以為 null。但是,您不能把 Map 作為一個鍵或值添加給自身。 
    •Object put(Object key, Object value) 
    •Object remove(Object key) 
    •void putAll(Map mapping) 
    •void clear() 

    查詢操作允許您檢查映射內容: 
    •Object get(Object key) 
    •boolean containsKey(Object key) 
    •boolean containsValue(Object value) 
    •int size() 
    •boolean isEmpty() 

    最后一組方法允許您把鍵或值的組作為集合來處理。 
    •public Set keySet() 
    •public Collection values() 
    •public Set entrySet() 

    因為映射中鍵的集合必須是唯一的,您用 Set 支持。因為映射中值的集合可能不唯一,您用 Collection 支持。最后一個方法返回一個實現 Map.Entry 接口的元素 Set。 

    Map.Entry 接口 

    Map 的 entrySet() 方法返回一個實現 Map.Entry 接口的對象集合。集合中每個對象都是底層 Map 中一個特定的鍵-值對。 

    通過這個集合迭代,您可以獲得每一條目的鍵或值并對值進行更改。但是,如果底層 Map 在 Map.Entry 接口的 setValue() 方法外部被修改,此條目集就會變得無效,并導致迭代器行為未定義。 

    HashMap 類和 TreeMap 類 

    “集合框架”提供兩種常規的 Map 實現:HashMap 和 TreeMap。和所有的具體實現一樣,使用哪種實現取決于您的特定需要。 在 Map 中插入、刪除和定位元素,HashMap 是最好的選擇。 但如果您要按順序遍歷鍵,那么 TreeMap 會更好。根據集合大小,先把元素添加到 HashMap,再把這種映射轉換成一個用于有序鍵遍歷的 TreeMap 可能更快。使用 HashMap 要求添加的鍵類明確定義了 hashCode() 實現。有了 TreeMap實現,添加到映射的元素一定是可排序的。我們將在排序中詳細介紹。 

    為了優化 HashMap 空間的使用,您可以調優初始容量和負載因子。這個 TreeMap 沒有調優選項,因為該樹總處于平衡狀態。 

    HashMap 和 TreeMap 都實現 Cloneable 接口。 

    Hashtable 類和 Properties 類是 Map接口的歷史實現。我們將在Dictionary 類、Hashtable 類和 Properties 類中討論。 

    映射的使用示例 

    以下程序演示了具體 Map 類的使用。該程序對自命令行傳遞的詞進行頻率計數。HashMap 起初用于數據存儲。后來,映射被轉換為 TreeMap 以顯示有序的鍵列列表。 
    import java.util.*; 

    public class MapExample { 
    public static void main(String args[]) { 
    Map map = new HashMap(); 
    Integer ONE = new Integer(1); 
    for (int i=0, n=args.length; i<n; i++) { >
    String key = args[i]; 
    Integer frequency = (Integer)map.get(key); 
    if (frequency == null) { 
    frequency = ONE; 
    } else { 
    int value = frequency.intValue(); 
    frequency = new Integer(value + 1); 

    map.put(key, frequency); 

    System.out.println(map); 
    Map sortedMap = new TreeMap(map); 
    System.out.println(sortedMap); 


    用 Bill of Rights 的第三篇文章的文本運行程序產生下列輸出,請注意有序輸出看起來多么有用! 

    無序輸出: 

    {prescribed=1, a=1, time=2, any=1, no=1, shall=1, nor=1, peace=1, owner=1, soldier=1, to=1, the=2, law=1, but=1, manner=1, without=1, house=1, in=4, by=1, consent=1, war=1, quartered=1, be=2, of=3} 

    有序輸出: 

    {a=1, any=1, be=2, but=1, by=1, consent=1, house=1, in=4, law=1, manner=1, no=1, nor=1, of=3, owner=1, peace=1, prescribed=1, quartered=1, shall=1, soldier=1, the=2, time=2, to=1, war=1, without=1} 

    AbstractMap 類 

    和其它抽象集合實現相似,AbstractMap 類覆蓋了 equals() 和 hashCode() 方法以確保兩個相等映射返回相同的散列碼。如果兩個映射大小相等、包含同樣的鍵且每個鍵在這兩個映射中對應的值都相同,則這兩個映射相等。按定義,映射的散列碼是映射元素散列碼的總和, 其中每個元素是 Map.Entry 接口的一個實現。因此,不論映射內部順序如何,兩個相等映射會報告相同的散列碼。 

    WeakHashMap 類 

    WeakHashMap 是 Map 的一個特殊實現,它只用于存儲對鍵的弱引用。 當映射的某個鍵在 WeakHashMap 的外部不再被引用時,就允許垃圾收集器收集映射中相應的鍵值對。 使用 WeakHashMap 有益于保持類似注冊表的數據結構,其中條目的鍵不再能被任何線程訪問時,此條目就沒用了。 

    Java 2 SDK,標準版,版本 1.3 添加了一個構造函數到 WeakHashMap,它接受 Map。在 Java 2 平臺版本 1.2 中,該構造函數只允許覆蓋缺省負載因子和初始容量設置,不允許在另一個映射的基礎上初始化映射(如 Map 接口文檔中所介紹)。 


    -------------------------------------------------------------------------------- 

    排序 

    為了用“集合框架”的額外部分把排序支持添加到 Java 2 SDK,版本 1.2,核心 Java 庫作了許多更改。 像 String 和 Integer 類如今實現 Comparable 接口以提供自然排序順序。 對于那些沒有自然順序的類、或者當您想要一個不同于自然順序的順序時,您可以實現 Comparator 接口來定義您自己的。 

    為了利用排序功能,“集合框架”提供了兩種使用該功能的接口:SortedSet 和 SortedMap。 

    Comparable 接口 

    在 java.lang 包中,Comparable 接口適用于一個類有自然順序的時候。假定對象集合是同一類型,該接口允許您把集合排序成自然順序。 

    compareTo() 方法比較當前實例和作為參數傳入的元素。如果排序過程中當前實例出現在參數前,就返回某個負值。如果當前實例出現在參數后,則返回正值。否則,返回零。這里不要求零返回值表示元素相等。零返回值只是表示兩個對象排在同一個位置。 

    在 Java 2 SDK,版本 1.2 中有十四個類實現 Comparable 接口。下表展示了它們的自然排序。 雖然一些類共享同一種自然排序,但只有相互可比的類才能排序。 

    類 排序 

    BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short 按數字大小排序 

    Character 按 Unicode 值的數字大小排序 

    CollationKey 按語言環境敏感的字符串排序 

    Date 按年代排序 

    File 按系統特定的路徑名的全限定字符的 Unicode 值排序 

    ObjectStreamField 按名字中字符的 Unicode 值排序 

    String 按字符串中字符 Unicode 值排序 


    String 的 compareTo() 方法的文檔按詞典的形式定義了排序。這意味著比較只是在文本中被數字化了的字符串值之間,其中文本沒有必要按所有語言的字母順序排序。 對于語言環境特定的排序,通過 CollationKey 使用 Collator。 

    下面演示了通過 CollationKey 使用 Collator 進行語言環境特定的排序: 
    import java.text.*; 
    import java.util.*; 

    public class CollatorTest { 
    public static void main(String args[]) { 
    Collator collator = Collator.getInstance(); 
    CollationKey key1 = collator.getCollationKey("Tom"); 
    CollationKey key2 = collator.getCollationKey("tom"); 
    CollationKey key3 = collator.getCollationKey("thom"); 
    CollationKey key4 = collator.getCollationKey("Thom"); 
    CollationKey key5 = collator.getCollationKey("Thomas"); 

    Set set = new TreeSet(); 
    set.add(key1); 
    set.add(key2); 
    set.add(key3); 
    set.add(key4); 
    set.add(key5); 
    printCollection(set); 

    static private void printCollection( 
    Collection collection) { 
    boolean first = true; 
    Iterator iterator = collection.iterator(); 
    System.out.print("["); 
    while (iterator.hasNext()) { 
    if (first) { 
    first = false; 
    } else { 
    System.out.print(", "); 

    CollationKey key = (CollationKey)iterator.next(); 
    System.out.print(key.getSourceString()); 

    System.out.println("]"); 


    運行程序產生了以下輸出。 
    [thom, Thom, Thomas, tom, Tom] 
    如果沒有用 Collator,而是直接的存儲名字,那么小寫的名字會和大寫的名字分開顯示: 
    [Thom, Thomas, Tom, thom, tom] 
    創建您自己的類 Comparable 只是個實現 compareTo() 方法的問題。通常就是依賴幾個數據成員的自然排序。您自己的類也應該覆蓋 equals() 和 hashCode() 以確保兩個相等的對象返回同一個散列碼。 

    Comparator 接口 

    若一個類不能用于實現 java.lang.Comparable,您可以提供自己的 java.util.Comparator 行為。如果您不喜歡缺省的 Comparable 行為,您照樣可以提供自己的 Comparator。 

    Comparator 的 compare() 方法的返回值和 Comparable 的 compareTo() 方法的返回值相似。在此情況下,如果排序時第一個元素出現在第二個元素之前,則返回一個負值。如果第一個元素出現在后,那么返回一個正值。 否則,返回零。與 Comparable 相似,零返回值不表示元素相等。一個零返回值只是表示兩個對象排在同一位置。由 Comparator 用戶決定如何處理。 如果兩個不相等的元素比較的結果為零,您首先應該確信那就是您要的結果,然后記錄行為。 

    為了演示,您會發現編寫一個新的忽略大小寫的 Comparator,代替使用 Collator 進行語言環境特定、忽略大小寫的比較會更容易。這樣的一種實現如下所示: 
    class CaseInsensitiveComparator implements Comparator { 
    public int compare(Object element1, Object element2) { 
    String lowerE1 = ((String)element1).toLowerCase(); 
    String lowerE2 = ((String)element2).toLowerCase(); 
    return lowerE1.compareTo(lowerE2); 


    因為每個類在某些地方都建立了 Object 子類,所以這不是您實現 equals() 方法的必要條件。實際上大多數情況下您不會去這樣做。切記該 equals() 方法檢查的是 Comparator 實現的等同性,不是處于比較狀態下的對象。 

    Collections 類有個預定義的 Comparator 用于重用。 調用 Collections.reverseOrder() 返回一個 Comparator,它對逆序實現 Comparable 接口的對象進行排序。 

    練習 
    •練習 4. 如何使用映射對詞計數 

    SortedSet 接口 

    “集合框架”提供了個特殊的 Set 接口:SortedSet,它保持元素的有序順序。 

    該接口為集的子集和它的兩端(即頭和尾)提供了訪問方法。當您處理列表的子集時,更改子集會反映到源集。 此外,更改源集也會反映在子集上。發生這種情況的原因在于子集由兩端的元素而不是下標元素指定。 此外,如果 fromElement 是源集的一部分,它就是子集的一部分。但如果 toElement 是源集的一部分,它卻不是子集的一部分。如果您想要一個特殊的高端元素(to-element)在子集中,您必須找到下一個元素。對于一個 String 來說,下一個元素是個附帶空字符的同一個字符串(string+"\0")。; 

    添加到 SortedSet 的元素必須實現 Comparable,否則您必須給它的實現類的構造函數提供一個 Comparator:TreeSet(您可以自己實現接口。但是“集合框架”只提供這樣一個具體的實現類。) 

    為了演示,以下示例使用 Collections 類中逆序的 Comparator。 
    Comparator comparator = Collections.reverseOrder(); 
    Set reverseSet = new TreeSet(comparator); 
    reverseSet.add("Bernadine"); 
    reverseSet.add("Elizabeth"); 
    reverseSet.add("Gene"); 
    reverseSet.add("Elizabeth"); 
    reverseSet.add("Clara"); 
    System.out.println(reverseSet); 
    運行程序產生了以下輸出。 
    [Gene, Elizabeth, Clara, Bernadine] 
    因為集必須包含唯一的項,如果添加元素時比較兩個元素導致了零返回值(通過 Comparable 的 compareTo() 方法或 Comparator 的 compare() 方法)那么新元素就沒有添加進去。如果兩個元素相等,那還好。但如果它們不相等的話,您接下來就應該修改比較方法,讓比較方法和 equals() 方法一致。 

    使用先前的 CaseInsensitiveComparator 演示這一問題,產生了一個三元素集:thom、Thomas 和 Tom,而不是可能預期的五個元素。 
    Comparator comparator = new CaseInsensitiveComparator(); 
    Set set = new TreeSet(comparator); 
    set.add("Tom"); 
    set.add("tom"); 
    set.add("thom"); 
    set.add("Thom"); 
    set.add("Thomas"); 

    SortedMap 接口 

    “集合框架”提供了個特殊的Map 接口:SortedMap,它用來保持鍵的有序順序。 

    此接口為映射的子集包括兩個端點提供了訪問方法。除了排序是作用于映射的鍵以外,處理 SortedMap 和處理 SortedSet 一樣。“集合框架”提供的實現類是 TreeMap。 

    因為對于映射來說,每個鍵只能對應一個值,如果在添加一個鍵-值對時比較兩個鍵產生了零返回值(通過 Comparable 的 compareTo() 方法或通過 Comparator 的 compare() 方法),那么,原始鍵對應值被新的值替代。如果兩個元素相等,那還好。 但如果不相等,那么您就應該修改比較方法,讓比較方法和 equals() 的效果一致。 

    posted on 2012-09-20 00:42 奮斗成就男人 閱讀(412) 評論(0)  編輯  收藏 所屬分類: java

    主站蜘蛛池模板: 国产精品亚洲а∨无码播放麻豆| 一级做a爰全过程免费视频毛片| 国产精品无码一区二区三区免费| 羞羞视频免费网站入口| 国产gv天堂亚洲国产gv刚刚碰| 最近中文字幕mv免费高清视频8 | 日本不卡在线观看免费v| 一级成人a做片免费| 99人中文字幕亚洲区| 国产人成免费视频| 最近免费中文字幕高清大全| 黄色毛片视频免费| 亚洲国产中文在线二区三区免| 亚洲性日韩精品国产一区二区| 国产91免费在线观看| 最新久久免费视频| 亚洲av无码专区亚洲av不卡| 亚洲av无码成人黄网站在线观看| 国产精品另类激情久久久免费| 久久一本岛在免费线观看2020| 国产亚洲日韩在线a不卡| 亚洲综合久久久久久中文字幕| 成人伊人亚洲人综合网站222| 国产免费女女脚奴视频网| 中国国产高清免费av片| 久久水蜜桃亚洲AV无码精品| 亚洲精品国产第1页| 欧洲亚洲国产清在高| 免费a级毛片视频| 91在线品视觉盛宴免费| 久别的草原电视剧免费观看| 免费高清A级毛片在线播放| 亚洲AV一二三区成人影片| 亚洲AV综合色区无码一区| 亚洲精品A在线观看| 日韩成人免费在线| 18禁超污无遮挡无码免费网站国产 | 在线免费观看国产| 日本免费高清视频| 一级日本高清视频免费观看| 视频一区二区三区免费观看|