List的有用實現
1.ArrayList 2.LinkedList 3.Vector 4.Stack
討論1:底層機制(牽扯到的資料結構的知識請讀者自行複習) ArrayList與Vector都是基於數組實現的,這就說明ArrayList與Vector適合做遍曆而不適合做頻繁的插入和刪除。 LinkedList是基於鏈表實現的,所以它生來就是為了頻繁插入與刪除對象。
討論2:特殊功能 Stack是一個後進先出(LIFO)對象堆棧,而LinkedList除可以被用作堆棧外,還可以被用作隊列或雙端隊列。 不同的是Stack繼承自Vector,也就是說它也是基於數組實現的。
討論3:記憶體佔用 基於數組實現的List,在動態擴充時會產生新的數組,然後把舊數組裡的內容複寫到新數組裡,這會產生大量的不再被使用的對象引用變數等待系統回收。而基於鏈表實現的List就不會有這種問題。
討論4:同步問題 Vector與Stack生來就是同步的,而ArrayList與LinkedList需要使用Collections.synchronizedList(List list)方法來轉換成同步List.從它們的對象上返回的迭代器是快速失敗的,也就是說在使用迭代器進行迭代的時候,必須使用迭代器本身的remove、add、set方法來添加或更改List元素,如果在迭代的同時,在其他線程中從結構上修改了List(結構上的修改是指任何添加或刪除一個或多個元素的操作,或者顯式調整底層數組的大小;僅僅設定元素的值不是結構上的修改),快速失敗迭代器會盡最大努力拋出ConcurrentModificationException.
討論5:使用原則 如果資料被從資料來源提取,資料量不確定,該資料一經被提取後就幾乎不會再添加或刪除,那麼應該建立一個LinkedList來儲存從資料來源中取出的資料,然後將該LinkedList轉換成ArrayList來最佳化遍曆操作。反過來,資料量確定的資料從資料來源取出可以先建立一個ArrayList來儲存,根據需要如需頻繁增刪,就轉換為LinkedList,如頻繁遍曆就不需轉換。 轉換的方法就是使用對應的List類來封裝目標List對象。如 ArrayList al = new ArrayList(); LinkedList ll = new LinkedList(al); 同理反過來也可以 LinkedList ll = new LinkedList(); ArrayList al = new ArrayList(ll);
討論6:toArray()方法 基於數組實現的List會直接返回一個底層數組的拷貝(使用了System.arraycopy方法),Examda提示: 基於鏈表實現的List會新產生一個數組。
討論7:不可修改 通過使用Collections.unmodifiableList(List list)來產生一個不可修改的List,試圖修改返回的列表,不管是直接修改還是通過其迭代器進行修改,都將導致拋出UnsupportedOperationException.
討論8:遍曆器 請盡量使用Iterator,Enumeration已不被鼓勵使用。 最後,請參考java.util.Collections類,該類提供了很多有用的操縱集合對象的方法。
Map介面常用的實作類別有:
1.HashMap 2.Hashtable 3.TreeMap 4.LinkedHashMap
討論1:底層機制 HashMap與Hashtable基於數組實現,TreeMap基於樹型結構,底層儲存結構是典型的鏈表結構。LinkedHashMap繼承自HashMap,所以也是基於數組實現的。
討論2:繼承關係 HashMap與TreeMap繼承自AbstractMap,Hashtable繼承自Dictionary,LinkedHashMap繼承自HashMap.
討論3:同步關係 Hashtable是同步的,而HashMap與TreeMap以及LinkedHashMap不是同步的,可以使用Collections中提供的方法轉換為同步的。
討論4:迭代器 迭代器都是快速失敗的(註:參考本系列第一篇List篇)
討論5:不可修改 通過使用Collections.unmodifiableMap(Map map)來轉換。