java基础系列:集合总结(6)
排序和搜索
數組
Arrays類為所有基本數據類型的數組提供了一個過載的 sort()和 binarySearch(),它們亦可用于 String 和Object。
public class Array1 {static Random r = new Random();static String ssource = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ "abcdefghijklmnopqrstuvwxyz";static char[] src = ssource.toCharArray();// Create a random Stringpublic static String randString(int length) {char[] buf = new char[length];int rnd;for (int i = 0; i < length; i++) {rnd = Math.abs(r.nextInt()) % src.length;buf[i] = src[rnd];}return new String(buf);}// Create a random array of Strings:public static String[] randStrings(int length, int size) {String[] s = new String[size];for (int i = 0; i < size; i++)s[i] = randString(length);return s;}public static void print(byte[] b) {for (int i = 0; i < b.length; i++)System.out.print(b[i] + " ");System.out.println();}public static void print(String[] s) {for (int i = 0; i < s.length; i++)System.out.print(s[i] + " ");System.out.println();}public static void main(String[] args) {byte[] b = new byte[15];r.nextBytes(b); // Fill with random bytesprint(b);Arrays.sort(b);print(b);int loc = Arrays.binarySearch(b, b[10]);System.out.println("Location of " + b[10] + " = " + loc);// Test String sort & search:String[] s = randStrings(4, 10);print(s);Arrays.sort(s);print(s);loc = Arrays.binarySearch(s, s[4]);System.out.println("Location of " + s[4] + " = " + loc);} }在 main()中, Random.nextBytes()
用隨機選擇的字節填充數組自變量(沒有對應的Random 方法用于創建其他基本數據類型的數組)。獲得一個數組后,便可發現為了執行 sort()或者 binarySearch(),只需發出一次方法調用即可。與 binarySearch()有關的還有一個重要的警告:若在執行一次 binarySearch()之前不調用 sort(),便會發生不可預測的行為,其中甚至包括無限循環。
對 String 的排序以及搜索是相似的,但在運行程序的時候,我們會注意到一個有趣的現象:排序遵守的是字典順序,亦即大寫字母在字符集中位于小寫字母的前面。因此,所有大寫字母都位于列表的最前面,后面再跟上小寫字母—— Z 居然位于 a 的前面。似乎連電話簿也是這樣排序的。
- 可比較與比較器
若想對一個 Object 數組進行排序,那么必須解決一個問題。根據什么來判定兩個 Object 的順序呢?不幸的是,最初的 Java 設計者并不認為這是一個重要的問題,否則就已經在根類 Object 里定義它了。這樣造成的一個后果便是:必須從外部進行 Object 的排序,而且新的集合庫提供了實現這一操作的標準方式(最理想的是在 Object 里定義它)。
針對 Object 數組(以及 String,它當然屬于 Object 的一種),可使用一個 sort(),并令其接納另一個參數:實現了 Comparator 接口(即“比較器”接口,新集合庫的一部分)的一個對象,并用它的單個compare()方法進行比較。這個方法將兩個準備比較的對象作為自己的參數使用—— 若第一個參數小于第二個,返回一個負整數;若相等,返回零;若第一個參數大于第二個,則返回正整數。基于這一規則,上述例子的 String 部分便可重新寫過,令其進行真正按字母順序的排序:
通過造型為 String, compare()方法會進行“暗示”性的測試,保證自己操作的只能是 String 對象—— 運期系統會捕獲任何差錯。將兩個字串都強迫換成小寫形式后, String.compareTo()方法會產生預期的結果若用自己的 Comparator 來進行一次 sort(),那么在使用 binarySearch()時必須使用那個相同的Comparator。
Arrays 類提供了另一個 sort()方法,它會采用單個自變量:一個 Object 數組,但沒有 Comparator。這個
sort()方法也必須用同樣的方式來比較兩個 Object。通過實現 Comparable 接口,它采用了賦予一個類的“自然比較方法”。 這個接口含有單獨一個方法—— compareTo(),能分別根據它小于、等于或者大于自變量而返回負數、零或者正數,從而實現對象的比較。
- 列表
可用與數組相同的形式排序和搜索一個列表( List)。用于排序和搜索列表的靜態方法包含在類Collections 中,但它們擁有與 Arrays 中差不多的簽名: sort(List)用于對一個實現了 Comparable 的對象列表進行排序; binarySearch(List,Object)用于查找列表中的某個對象; sort(List,Comparator)利用一個“比較器”對一個列表進行排序;而binarySearch(List,Object,Comparator)則用于查找那個列表中的一個對象
這些方法的用法與在 Arrays 中的用法是完全一致的,只是用一個列表代替了數組。
TreeMap 也必須根據 Comparable 或者 Comparator 對自己的對象進行排序
Collections 類中的實用工具:
enumeration(Collection) 為自變量產生原始風格的 Enumeration(枚舉)
max(Collection), min(Collection) 在自變量中用集合內對象的自然比較方法產生最大或最小元素
max(Collection,Comparator), min(Collection,Comparator) 在集合內用比較器產生最大或最小元素
nCopies(int n, Object o) 返回長度為 n 的一個不可變列表,它的所有句柄均指向 o
subList(List,int min,int max) 返回由指定參數列表后推得到的一個新列表。可將這個列表想象成一個
“窗口”,它自索引為 min 的地方開始,正好結束于 max 的前面
注意 min()和 max()都是隨同 Collection 對象工作的,而非隨同 List,所以不必擔心 Collection 是否需要排序(就象早先指出的那樣,在執行一次 binarySearch()—— 即二進制搜索—— 之前,必須對一個 List 或者一個數組執行 sort())
1. 使 Collection 或 Map 不可修改
通常,創建 Collection 或 Map 的一個“只讀”版本顯得更有利一些。 Collections 類允許我們達到這個目標,方法是將原始容器傳遞進入一個方法,并令其傳回一個只讀版本。這個方法共有四種變化形式,分別用于 Collection(如果不想把集合當作一種更特殊的類型對待)、 List、 Set 以及 Map。
public class ReadOnly {public static void main(String[] args) {Collection c = new ArrayList();Collection1.fill(c); // Insert useful datac = Collections.unmodifiableCollection(c);Collection1.print(c); // Reading is OK// ! c.add("one"); // Can't change itList a = new ArrayList();Collection1.fill(a);a = Collections.unmodifiableList(a);ListIterator lit = a.listIterator();System.out.println(lit.next()); // Reading OK// ! lit.add("one"); // Can't change itSet s = new HashSet();Collection1.fill(s);s = Collections.unmodifiableSet(s);Collection1.print(s); // Reading OK// ! s.add("one"); // Can't change itMap m = new HashMap();Map1.fill(m, Map1.testData1);m = Collections.unmodifiableMap(m);Map1.print(m); // Reading OK// ! m.put("Ralph", "Howdy!");} }對于每種情況,在將其正式變為只讀以前,都必須用有有效的數據填充容器。一旦載入成功,最佳的做法就是用“不可修改”調用產生的句柄替換現有的句柄。這樣做可有效避免將其變成不可修改后不慎改變其中的內容。
在另一方面,該工具也允許我們在一個類中將能夠修改的容器保持為private 狀態,并可從一個方法調用中返回指向那個容器的一個只讀句柄。這樣一來,雖然我們可在類里修改它,但其他任何人都只能讀。
為特定類型調用“不可修改”的方法不會造成編譯期間的檢查,但一旦發生任何變化,對修改特定容器的方法的調用便會產生一個 UnsupportedOperationException 違例。
2.Collection 或 Map 的同步
在這兒,大家只需注意到 Collections 類提供了對整個容器進行自動同步的一種途徑。它的語法與“不可修改”的方法是類似的:
public class Synchronization {public static void main(String[] args) {Collection c = Collections.synchronizedCollection(new ArrayList());List list = Collections.synchronizedList(new ArrayList());Set s = Collections.synchronizedSet(new HashSet());Map m = Collections.synchronizedMap(new HashMap());} }總結
(1) 數組包含了對象的數字化索引。它容納的是一種已知類型的對象,所以在查找一個對象時,不必對結果進行造型處理。數組可以是多維的,而且能夠容納基本數據類型。但是,一旦把它創建好以后,大小便不能變化了。
(2) Vector(矢量)也包含了對象的數字索引—— 可將數組和 Vector 想象成隨機訪問集合。當我們加入更多的元素時, Vector 能夠自動改變自身的大小。但 Vector 只能容納對象的句柄,所以它不可包含基本數據類型;而且將一個對象句柄從集合中取出來的時候,必須對結果進行造型處理。
(3) Hashtable(散列表)屬于 Dictionary(字典)的一種類型,是一種將對象(而不是數字)同其他對象關聯到一起的方式。散列表也支持對對象的隨機訪問,事實上,它的整個設計方案都在突出訪問的“高速度”。
(4) Stack(堆棧)是一種“后入先出”( LIFO)的隊列
對于 Hashtable,可將任何東西置入其中,并以非常快的速度檢索;對于 Enumeration(枚舉),可遍歷一個序列,并對其中的每個元素都采取一個特定的操作。那是一種功能足夠強勁的工具。
但 Hashtable 沒有“順序”的概念。 Vector 和數組為我們提供了一種線性順序,但若要把一個元素插入它們任何一個的中部,一般都要付出“慘重”的代價。除此以外,隊列、拆散隊列、優先級隊列以及樹都涉及到元素的“排序” —— 并非僅僅將它們置入,以便以后能按線性順序查找或移動它們。
總結
以上是生活随笔為你收集整理的java基础系列:集合总结(6)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java基础系列:集合总结(5)
- 下一篇: java基础系列:集合总结(7)