瞭解新的集合型別及現有類和介面的附加特性
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
使用 Java 5。0 平臺,您可能以為:由於將集合宣告為通用集合 (Collection
三個 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
清單 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()) 。