程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 馴服Tiger - 集合框架

馴服Tiger - 集合框架

編輯:關於JAVA

JDK 5.0 中最吸引人的地方在於集合框架的一些最突出的特性上,例如:支 持泛型的語言級別上的新變化,以及可以在 java.util.concurrent 包中找到的 並發集合工具包。實際上,以前在 developerWorks 上的“馴服 Tiger: 並發集 合”和“介紹 JDK 5.0 中的泛型”這兩篇教程中介紹了上述特性。但是其他增 強還沒有得到足夠的重視。在本文中,我將研究其他三個變化:更新過的 Arrays 和 Collections 類、新的 Queue 接口以及它的 PriorityQueue 實現。

數組(Array)

Arrays 類提供了一系列處理數組的靜態工具方法,這些索引的數據結構的大 小是固定的。在 5.0 版本之前,Arrays 類擁有針對原始數據庫類型和通用 Object 類型的每種不同數組類型的 binarySearch()、equals()、fill() 和 sort() 方法。用於將 Object 數組轉換成 List 的附加 asList() 方法仍然有 用。Tiger 為所有數組添加了 hashCode() 和 toString() 方法,還添加了特定 於 Object 數組的 deepEquals()、deepHashCode() 和 deepToString() 方法。 總計有 21 個新方法可用:

public static boolean deepEquals(Object[] a1, Object[] a2)

public static int deepHashCode(Object[] a)

public static String deepToString(Object[] a)

public static int hashCode(boolean[] a)

public static int hashCode(byte[] a)

public static int hashCode(char[] a)

public static int hashCode(double[] a)

public static int hashCode(float[] a)

public static int hashCode(int[] a)

public static int hashCode(long[] a)

public static int hashCode(Object[] a)

public static int hashCode(short[] a)

public static String toString(boolean[] a)

public static String toString(byte[] a)

public static String toString(char[] a)

public static String toString(double[] a)

public static String toString(float[] a)

public static String toString(int[] a)

public static String toString(long[] a)

public static String toString(Object[] a)

public static String toString(short[] a)

自從集合框架初次出現在 J2SE 1.2 中以來,人們第一次對實用工具類進行 了更改。我無法確定為什麼 Sun 要等這麼久才進行更改,但是對於可用的幫助 器方法系列來說,這些更改是受歡迎的添加。

新添加的第一個方法是 hashCode()。對於任意數組類型,都可以調用 Arrays.hashCode(arrayVar) 方法來獲得格式良好的哈希碼。這個哈希碼可以用 作 HashMap 或者其他相關目的的鍵。如果您不知道如何生成良好的哈希碼,那 麼最好使用 Arrays 類,它能產生更少沖突。Arrays 類生成等價於擁有相同元 素的 List 的代碼。

在創建自己的類時,既需要提供 equals() 方法,又需要提供 hashCode() 方法。在 Arrays 的新方法 hashCode() 的幫助下,可以為任何本地數組類型生 成哈希碼,而不用在每次需要它的時候折騰您自己。

所有數組類型都可用的另一個方法是 toString()。對於任何數組類型,都可 以調用 Arrays.toString(arrayVar) 獲得逗號分隔的元素列表,列表用方括號 包圍,如清單 1 的程序所示:

清單 1. 用 Arrays.toString 生成字符串

import java.util.Arrays;
public class ArgsToString {
  public static void main(String args[]) {
   System.out.println(Arrays.toString(args));
  }
}

清單 2 顯示了結果:

清單 2. 清單 1 的結果

>java ArgsToString One Two Three
  [One, Two, Three]

新的 deepEquals()、deepHashCode() 和 deepToString() 方法的工作方式 類似於它們那些非深度(non-deep)的同類,但它們不僅會停下手來處理頂級數 組的每個元素,還會更深入地研究生成結果的多維數組。

雖然不是一個新方法,但 asList() 方法在 5.0 的工作方式有所不同。以前 ,這個方法接受 Object[] 數組作為它的參數。現在,因為 Tiger 的可變參數 列表特性,任何用逗號分隔的列表都可以接受,如清單 3 所示:

清單 3. Arrays.asList 的區別

import java.util.Arrays;
public class AsList {
  public static void main(String args[]) {
   // Before
   List before = Arrays.asList(args);
   // After
   List after = Arrays.asList("One", "Two", "Three");
  }
}

如果傳遞給命令行的元素不同,清單 3 中的兩個示例沒必要產生同樣的結果 ,但是它確實展示了 Tiger 在語言級別上的變化如何擴展了 Arrays 原有的 asList() 方法。

集合

Arrays 用於處理不同集合的輔助類是 Collections 類。同樣,這個類也不 是一個新類,但是該類的特性已經針對 5.0 作了擴展。現在有 13 個新方法:

checkedCollection()

checkedSet()

checkedSortedSet()

checkedList()

checkedMap()

checkedSortedMap()

emptySet()

emptyList()

emptyMap()

reverseOrder()

frequency()

disjoint()

addAll()

其中 6 個 checked*() 方法工作起來與 6 個 synchronized*() 和 unmodifiable*() 方法類似。使用 synchronized*() 方法時,要向該方法提供 一個集合,然後該方法將返回同一個集合的同步的、線程安全的版本。使用 unmodifiable*() 方法時,得到的是指定集合的只讀視圖。除了集合參數之外, checked*() 操作可能還要求第二個或者第三個參數(如清單 4 所示),並返回 該集合的動態的類型安全視圖:

清單 4. 檢測後的集合

public static <E> Collection<E> checkedCollection(
   Collection<E> c, Class<E> type)
  public static <E> Set<E> checkedSet(
   Set<E> s, Class<E> type)
  public static <E> SortedSet<E> checkedSortedSet(
   SortedSet<E> s, Class<E> type)
  public static <E> List<E> checkedList(
   List<E> list, Class<E> type)
  public static <K,V> Map<K,V> checkedMap(
   Map<K,V> m, Class<K> keyType, Class<V> valueType)
  public static <K,V> SortedMap<K,V> checkedSortedMap (
   SortedMap<K,V> m, Class<K> keyType, Class<V> valueType)

使用 Java 5.0 平台,您可能以為:由於將集合聲明為通用集合 (Collection<String> c = new HashSet<String>();),所以不 需要進行運行時檢測了。但是如果向工具方法傳遞 String 版本的 HashSet,而 工具方法只能處理非通用的 Set,那麼該方法可能就會錯誤地向集合添加一個非 String 元素。通過臨時修改程序,用 Collection<String> c = Collections.checkedCollection(new HashSet<String>(), String.class); 添加運行時檢查,您可以迅速發現問題的根源。

三個 empty*() 方法 —— emptySet()、emptyList() 和 emptyMap() —— 生成空的不可改變的集合。雖然也可以用 new ArraySet() 這樣的方法創建空集 合,但是還要通過某個 unmodifiable*() 方法才能確保新集合是不可改變的。 empty 方法用更理想的方式提供了空的只讀集合。

隊列(Queue)接口

5.0 集合框架較大的一個改變就是添加了新的基接口 Queue。雖然這個接口 是在“並發集合”技巧 (請參閱 參考資料)中描述的,但它的應用並不限於並 發。在計算機科學中,隊列數據結構是基本的先進先出(FIFO) 結構。項目添 加到尾部,並且要從頂部刪除。不僅能添加和刪除元素,還能查看隊列中有哪些 元素。清單 5 顯示了 Queue 接口的 5 個方法:

清單 5. Queue 接口

public boolean offer(Object element)
  public Object remove()
  public Object poll()
  public Object element()
  public Object peek()

請記住,Queue 是從 Collection 接口擴展的,所以實現 Queue 接口也就實 現了 Collection。在使用 Queue 的實現時,應當將自己限制在接口的方法上。 例如,向 Queue 添加元素可以用 Collection 的 add() 方法來實現,它在失敗 時會拋出未檢測異常。相反,如果大小有限的隊列滿了,那麼 offer() 方法會 返回 false,而不需要處理隊列滿的異常。

java.util.concurrent 包中具有 Queue 接口的多個實現,但並不包含所有 實現。LinkedList 類針對 JDK 5.0 的 Queue 接口作了修正,而 PriorityQueue 是隨 JDK 5.0 添加進來的。余下的實現 —— ArrayBlockingQueue、ConcurrentLinkedQueue、DelayQueue、 LinkedBlockingQueue、PriorityBlockingQueue 和 SynchronousQueue —— 都 是 java.util.concurrent 包的組成部分。

因為 LinkedList 不是新事物,所以我們來看一下新的 PriorityQueue 類。 如清單 6 所示,可以用 6 種方法創建它。在不能使用 Comparator 時,可以使 用元素的自然順序來確定優先級。如果元素沒有實現 Comparable 接口,那麼就 會產生運行時錯誤:

清單 6. PriorityQueue 構造函數

PriorityQueue()
  PriorityQueue(Collection<? extends E> c)
  PriorityQueue(int initialCapacity)
  PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
  PriorityQueue(PriorityQueue<? extends E> c)
  PriorityQueue(SortedSet<? extends E> c)

為了演示 PriorityQueue 的用法,清單 7 中的程序添加了所有命令行元素 ,並按字母順序處理它們。由於隊列結構是 LinkedList,所以順序應當是典型 的 FIFO 順序,但是 PriorityQueue 將根據優先級對元素進行排序:

清單 7. PriorityQueue 的用法

import java.util.*;
import java.util.concurrent.*;
public class Priority {
  public static void main(String args[]) {
   Queue<String> queue =
    new PriorityQueue<String>(Arrays.asList(args));
   String element;
   while ((element = queue.poll()) != null) {
     System.out.println(element);
   }
  }
}

清單 8 顯示了用命令行 one two three four 運行程序之後的輸出 :

清單 8. 清單 7 的結果

>java Priority one two three four
  four
  one
  three
  two

關於新的 Queue 接口,有件事需要提一下,這件事與 Collections 類有關 :方法 checkedQueue()、emptyQueue()、synchronizedQueue() 和 unmodifiableQueue() 全都是 Collections 類中所缺少的。根據 bug 報告,除 了 checkedQueue() 之外,所有類都是故意缺失的。對於 synchronizedQueue() ,並發集合是比純粹的包裝器更好的選擇。其他方法則被認為不是必需的。也許 Tiger/6.0 版本中會添加 checkedQueue()(和 checkedBlockingQueue()) 。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved