《thinking in java》學習手記(四)
來源:互聯網
上載者:User
1、數組 數組與其它容器的區別在於:它可以持有privitive對象,效率高。 盡量先考慮使用數組。 數組的複製System.arrayCopy()。這個拷貝是淺拷貝(即對對象數組而言,拷貝的是reference數組。2、Arrays類 這個類有四個靜態方法:數組是否相等equals();填充數組fill();對數組進行排序sort();在一個已排序的數組中尋找數組binarySearch();此外還有一個asList()方法。3、數組元素的比較 有兩種方式可以實現數組元素的比較: 1)實現java.lang.Comparable介面。它只有一個方法compareTo()。這個方法能接收一個對象為參數,如果現有對象比參數對象小則返負數,相等則返0,比參數對象大則返正數。只要實現這個介面方法,該類就可以成功完成equals、sort等比較大小的操作。 2)經常會有這樣一些類,這些類並沒有實現Comparable介面。我們不能強制將這些類重寫一遍,以加進CompareTo方法。我們可以通過實現另一個介面:Comparator來解決問題。這個介面有兩個方法:compare和equals。而equals一般不需要特別實現,主要是compare。 這種方式就是:類 和 比較方法 完全分開。(與前一種方式有顯著差別) 比方說:類String有自訂的compare方法,”A” “b” “C”的排序將為: ACb,可能不是我們期望的AbC。這時我們可以這樣:import java.util.*;public class ArraysTest { public static void main(String[] args) { // TODO Auto-generated method stub String[] s = { "A", "b", "C" }; Arrays.sort( s, new AC()); System.out.println( Arrays.asList(s)); }} class AC implements Comparator{ public int compare( Object obj1,Object obj2){ String s1 = (String)obj1; String s2 = (String)obj2; return s1.toLowerCase().compareTo(s2.toLowerCase()); } }4、尋找 必須注意一個問題:數組的尋找先通過sort之後才有意義。但在這樣的情況中,即便經過sort,尋找也是沒有意義的:例如String的compare比較子是臨時指定的,而不是String類自身的,就象上面那個常式一樣。因為binarySearch用的比較子只能是類預設的比較子。 比如”A” “b” “C”可以排成AbC,但尋找b就會找不到。 解決的辦法是把binarySearch的第三個參數加上,即指定比較子,用法同常式的sort()。 同時,設有五個串abcde,如果找“1”,則返-1。這個-1的含義是這樣的:1應該被插在第一個位置,但實際上沒查到。5、容器類 容器類是java中比較複雜的一個類。其容器類要解決“怎樣持有對象”的問題。而它把這個問題分成兩類: 1)Collection:一組有一定規律的獨立元素。分為List和Set。 2)Map:一組以“鍵——值”形式出現的pairs。本質上,它也是Collection。它的鍵可以提取出來成為Set,它的值也可以提取為Collection,當然pair本身也可以提取成Set。 Map可以很容易地擴充成多維。這隻要將值設成Map就行了。 選擇不同容器類,應注意下面兩個主要問題:重複性;插入順序。6、數組的工具在Arrays中,而Collection的工具則在Collections中。7、容器的缺點——不知道對象的類型 例如你定義了Dog和Pig,都可以放進同一容器內。但提取的時候,一定要做強制類型轉換,同時使用try關鍵字。 但有時,即便你不知道物件類型,一樣能正常使用。例如toString()方法。8、迭代器的好處是:提供一種脫鉤機制,讓你不加區別地遍曆集合,而不管集合的具體實現。這是一種設計模式。 應儘可能多地使用迭代器。例如有的集合類型是用下標訪問,有的不能用下標訪問,這時如果集合類型需要發生改變,則必須改動相應代碼。而如果一直使用迭代器,則一般情況下只需要變動變數定義。9、容器分類學 容器分類圖應再三溫習。這個圖相當重要。 與存放對象有關的介面主要是:Collection(Set、List)、Map這幾種。在理想情況下,我們應只同這些介面打交道。在絕大多數情況下這也夠用了。 例如,我們應該定義:List x = new LinkedList();注意前面是介面定義。這種定義方式可以很方便地實現容器轉型。如改成x = new ArrayList(),而無需驚動其它代碼。這就是這種方式的優雅之處。 從這些例子中,我們可以看到:有數字下標的是List,沒有下標的是Set(所以它無序,不支援隨機訪問),有對象下標的是Map。10、List 其特點就是有序。它會按一定順序來儲存元素,並且可以實現在List中的增刪等操作(對ArrayList不適合,因速度慢)。可以製造ListIterator對象,以便雙向遍曆。 實際上有兩種List:ArrayList:擅長隨機訪問。 LinkedList:鏈表,擅長插入、刪除等操作,適合順序訪問。能當成棧、隊列、雙向隊列使用。11、Set Set介面與Collection完全一樣,並且其中的元素是無序的。 加入Set的每一個元素都是唯一的。因此,構成每一個Set的元素(Object)必須實現equals方法。 有如下三種實現: 1)HashSet。這是為最佳化查詢而實現的Set,沒有其它意義,僅僅是查詢快而已。不儲存插入順序。 2)TreeSet。是一個有序的Set。這樣就可以從Set中提取一個有序序列。這裡的有序並非象List那樣的索引順序,而是元素自身的先後順序。這在對集合排序時是相當有用的。 3)LinkedHashSet。既有HashSet的優點,又儲存插入順序。這樣用Iterator來遍曆時,將得到一個按插入順序排序的序列。 如下方法可以得到類名:如instance是一個TreeSet。 instance.getClass():得到class com.p9pip.util.TreeSet instance.getClass().getName():得到: com.p9pip.util.TreeSet instance.getClass().getName().replaceAll(“//w+//.”,””):得到TreeSet。 其中replaceAll中用到了Regex,一個爽字!如果自己實現,非得寫一個函數不可。12、SortedSet(TreeSet的基類) 有一些單獨的專為排序實現的方法: 1)Comparator comparator():返回比較子。如果用Object的,則返回null。 2)Object first():返回最小的元素。 3)Object last():返回最大的元素。 4)SortedSet subSet(fromElement, toElement):返回Set的子集。其中的元素從fromElement到toElement(不包括toElement)。 5)SortedSet headSet(toElement):返回小於toElement的所有元素。 6)SortedSet tailSet(fromElement):返回大於等於fromElement的所有元素。 TreeSet只不過繼承了SortedSet抽象類別……13、Map 站在更為抽象的角度,ArrayList和Map都是同一類型的對象,它們都是用下標來尋找。而前者的下標是數字,後者是對象。同時,前者效率較低,但佔用空間相對較小。後者效率較高,但佔用空間卻較大。 幾種Map類的差異在於:效率,持有和表示對象pair的順序,持有對象的時間長短,如何決定鍵的相等性。 主要有下面幾種Map類: 1)HashMap:利用Hash演算法實現Map。這個類用來代替Hashtable。建構函式中可以提供capacity和load factory。 2)LinkedHashMap:很象HashMap,但結合了鏈表的特性。這樣:常規查詢時效能較HashMap稍低,而用Iterator遍曆時較HashMap為高。 3)TreeMap:基於紅/黑樹狀結構的資料結構實現。一個有序的Map實現。它有subMap方法,從而得到一棵子樹。為此,元素必須實現Comparable介面,或另外提供比較子Comparator。 4)WeakHashMap和IdentityHashMap:不常用。 必須注意:對於Map的值(value)可能產生變化的情形,不能使用primitive的wrapper類(如Integer等)。因這些值一旦賦值,就只能讀取(想想Integer等類中有哪些方法就明白了)。必須另外實現相應的類。14、SortedMap(TreeMap的基類) 與SortedSet極為相似,包括方法。15、Hashtable、Vector、Stack屬於老版本留下來的類16、選擇實現 容器與容器的區別,在於相應介面背後的資料結構實現。16.1 如何挑選List 1)處理固定數量的元素,用數組; 2)處理大量插入刪除,用LinkedList; 3)處理順序讀取,用ArrayList。 一般而言,先用ArrayList,一旦發現有大量插刪操作,將其直接改為LinkedList即可。這二者效能相差相當大。16.2 如何挑選Set 一般選HashSet就夠用了。須加快遍曆速度,則用LinkedHashSet。須排序,用TreeSet。 這三者效能十分接近。16.3 如何挑選Map 一般選HashMap就夠用了。須排序選用TreeMap。至於LinkedHashMap,一般不用。 這三者效能十分接近。