ArrayList、LinkedList、 Vector、Map 用法比较
ArrayList和Vector是采用數組方式存儲數據,此數組元素總數大于實際存儲的數據個數以便增加和插入元素,二者都允許直接序號索引元素,但是插入數據要移動數組元素等內存操作,所以它們索引數據快、插入數據慢。
ArrayList數組存儲方式:
[java]?view plaincopy print?
Vector由于使用了synchronized同步方法(如add、insert、remove、set、equals、hashcode等操作),因此是線程安全,性能上比ArrayList要差。
Vector數組存儲方式:
[java]?view plaincopy print?
LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向后遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入數度較快!
LinkedList雙向鏈表,是指可以從first依次遍歷至last(從頭到尾),也可以從last遍歷至first(從尾到頭),但首尾沒有構成環,不同于雙向循環鏈表(注意區分):
[java]?view plaincopy print?
其中,Node類結構如下:
[java]?view plaincopy print?
線性表、鏈表、哈希表是常用的數據結構,在進行Java開發時,JDK已經為我們提供了一系列相應的類來實現基本的數據結構,這些類均在java.util包中。
Collection? ? ? ? ??|--------List?
? ? ? ??? ? ? ? ? ??|----------LinkedList?
? ? ? ??? ? ? ? ? ??|----------ArrayList?
? ? ? ??? ? ? ? ? ??|----------Vector?
? ? ? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|-----Stack?
? ? ? ??|--------Set?
? ? ? ??? ? ? ? ? ??|----------HashSet.?
? ? ? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|-----LinkedHashSet?
? ? ? ??? ? ? ? ? ??|----------SortedSet?
? ? ? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|-----TreeSet?
Collection.?
● 實現該接口及其子接口的所有類都可應用clone()方法,并是序列化類.?
.....List.?
.....● 可隨機訪問包含的元素?
.....● 元素是有序的?
.....● 可在任意位置增、刪元素?
.....● 不管訪問多少次,元素位置不變?
.....● 允許重復元素?
.....● 用Iterator實現單向遍歷,也可用ListIterator實現雙向遍歷?
..........ArrayList?
..........● 用數組作為根本的數據結構來實現List?
..........● 元素順序存儲?
..........● 新增元素改變List大小時,內部會新建一個數組,在將添加元素前將所有數據拷貝到新數組中?
..........● 隨機訪問很快,刪除非頭尾元素慢,新增元素慢而且費資源?
..........● 較適用于無頻繁增刪的情況?
..........● 比數組效率低,如果不是需要可變數組,可考慮使用數組?
..........● 非線程安全?
..........Vector.?
..........● 另一種ArrayList,具備ArrayList的特性?
..........● 所有方法都是線程安全的(雙刃劍,和ArrayList的主要區別)?
..........● 比ArrayList效率低?
...............Stack?
...............● LIFO的數據結構?
..........LinkedList.?
..........● 鏈接對象數據結構(類似鏈表)?
..........● 隨機訪問很慢,增刪操作很快,不耗費多余資源?
..........● 非線程安全?
.....Set.?
.....● 不允許重復元素,可以有一個空元素?
.....● 不可隨機訪問包含的元素?
.....● 只能用Iterator實現單向遍歷?
..........HashSet?
..........● 用HashMap作為根本數據結構來實現Set?
..........● 元素是無序的?
..........● 迭代訪問元素的順序和加入的順序不同?
..........● 多次迭代訪問,元素的順序可能不同?
..........● 非線程安全?
...............LinkedHashSet?
...............● 基于HashMap和鏈表的Set實現?
...............● 迭代訪問元素的順序和加入的順序相同?
...............● 多次迭代訪問,元素的順序不變??
...............● 因此可說這是一種有序的數據結構?
...............● 性能比HashSet差?
...............● 非線程安全?
..........SortedSet?
..........● 加入SortedSet的所有元素必須實現Comparable接口?
..........● 元素是有序的?
...............TreeSet.?
...............● 基于TreeMap實現的SortedSet?
...............● 排序后按升序排列元素?
...............● 非線程安全?
Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行,一些能排序而另一些不行。Java?SDK不提供直接繼承自Collection的類,Java?SDK提供的類都是繼承自Collection的“子接口”如List和Set。
所有實現Collection接口的類都必須提供兩個標準的構造函數:
1)無參數的構造函數,用于創建一個空的Collection
2)有一個Collection參數的構造函數,用于創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。
后一個構造函數允許用戶復制一個Collection。
如何遍歷Collection中的每一個元素?
不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:
Iterator?it?=?collection.iterator();?//?獲得一個迭代子while(it.hasNext())?{
Object?obj?=?it.next();?//?得到下一個元素
}
由Collection接口派生的兩個接口是List和Set。
List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。 和下面要提到的Set不同,List允許有相同的元素。
除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向后遍歷。
實現List接口的常用類有LinkedList,ArrayList, Vector 和Stack。
LinkedList實現了List接口,允許null元素。此外在LinkedList的首部或尾部提供額外的get、remove、insert方法。
這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
注意:LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:List?list?=?Collections.synchronizedList(new?LinkedList(...));
ArrayList類
ArrayList實現了可變大小的數組,它允許所有元素,包括null,沒有同步。
size、isEmpty、get、set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間,其他的方法運行時間為線性。
每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法并沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
ArrayList擴展容量:
[java]?view plaincopy print?
和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。
Vector類
Vector非常類似ArrayList,但是Vector是同步的。
由Vector創建的Iterator,雖然和ArrayList創建的Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該異常。
Stack?類
Stack繼承自Vector,也是同步的,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。
Stack剛創建后是空棧。
Set是一種不包含重復的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。
很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重復的元素。Set?沒有同步方法。
注意:必須小心操作可變對象(Mutable?Object)。如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。
Map?
? ? ?|------Hashtable?? ? ?? ? ? ? ? |------Properties?
? ? ?|------HashMap?
? ? ?? ? ? ? ??|------LinkedHashMap?
? ? ?|------WeakHashMap?
? ? ?|------SortedMap?
?? ? ? ? ??? ? ?|------TreeMap
Map?
● 鍵值對,鍵和值一一對應?
● 不允許重復的鍵.?
.....Hashtable.?
.....● 用作鍵的對象必須實現了hashcode()、equals()方法,也就是說只有Object及其子類可用作鍵?
.....● 鍵、值都不能是空對象?
.....● 多次訪問,映射元素的順序相同?
.....● 線程安全的?
..........Properties?
..........● 鍵和值都是字符串?
.....HashMap?
.....● 鍵和值都可以是空對象?
.....● 不保證映射的順序?
.....● 多次訪問,映射元素的順序可能不同?
.....● 非線程安全?
...............LinkedHashMap?
...............● 多次訪問,映射元素的順序是相同的?
...............● 性能比HashMap差?
.....WeakHashMap..?
.....● 當某個鍵不再正常使用時,垃圾收集器會移除它,即便有映射關系存在?
.....● 非線程安全?
.....SortedMap.?
.....● 鍵按升序排列?
.....● 所有鍵都必須實現.Comparable.接口.?
...............TreeMap.?
...............● 基于紅黑樹的SortedMap實現?
...............● 非線程安全
Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個value。
Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。
Map接口定義:
[java]?view plaincopy print?
Hashtable類
Hashtable 繼承于Dictionary字典,實現Map接口,完成一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。
添加數據使用put(key,?value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。
Hashtable通過initial?capacity和load?factor兩個參數調整性能。通常缺省的load?factor?0.75較好地實現了時間和空間的均衡。增大load?factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。
Hashtable的構造實現:
[java]?view plaincopy print?
使用 Hashtable 的簡單示例如下,將1,2,3放到 Hashtable 中,他們的key分別是”one”,”two”,”three”:
Hashtable?numbers?=?new?Hashtable();
numbers.put(“one”,?new?Integer(1));
numbers.put(“two”,?new?Integer(2));
numbers.put(“three”,?new?Integer(3));
要取出一個數,比如2,用相應的key:
Integer?n?=?(Integer)numbers.get(“two”);
System.out.println(“two?=?”?+?n);
由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方法。
hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。
如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。
Hashtable 是同步的(函數體由synchronized修飾)。HashMap類
HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null?value和null?key。
但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load?factor過低。
HashMap的構造實現:
WeakHashMap類
WeakHashMap是一種改進的HashMap,也是非同步的,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。
使用場景比較 1) 同步性
Vector是同步的。這個類中的一些方法保證了Vector中的對象是線程安全的。
ArrayList則是異步的,因此ArrayList中的對象并不是線程安全的。
因為同步的要求會影響執行的效率,所以如果你不需要線程安全的集合那么使用ArrayList是一個很好的選擇,這樣可以避免由于同步帶來的不必要的性能開銷。
2)?數據增長
從內部實現機制來講ArrayList和Vector都是使用數組(Array)來控制集合中的對象。
當你向這兩種類型中增加(插入)元素的時候,如果元素的數目超出了內部數組目前的長度,它們都需要擴展內部數組的長度,Vector缺省情況下自動增長原來一倍的數組長度,ArrayList是原來的50%,所以最后你獲得的這個集合所占的空間總是比你實際需要的要大。所以如果你要在集合中保存大量的數據那么使用Vector有一些優勢,因為你可以通過設置集合的初始化大小來避免不必要的資源開銷。
3)?使用模式
在ArrayList和Vector中,從一個指定的位置(通過索引)查找數據或是在集合的末尾增加、移除一個元素所花費的時間是一樣的,這個時間我們用O(1)表示。
但是,如果在集合的其他位置增加或移除元素那么花費的時間會呈線形增長:O(n-i),其中n代表集合中元素的個數,i代表元素增加或移除元素的索引位置。為什么會這樣呢?以為在進行上述操作的時候集合中第i和第i個元素之后的所有元素都要執行位移的操作。這一切意味著什么呢?
這意味著,你只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是其他操作,你最好選擇其他的集合操作類。比如,LinkList集合類在增加或移除集合中任何位置的元素所花費的時間都是一樣的?O(1),但它在查詢索引一個元素的使用時卻比較慢O(i),其中i是索引的位置。
使用ArrayList也很容易,因為你可以簡單的使用索引來代替創建iterator對象的操作。
LinkList也會為每個插入的元素創建對象,所有你要明白它也會帶來額外的開銷。
最后,在《Practical?Java》一書中Peter?Haggar建議使用一個簡單的數組(Array)來代替Vector或ArrayList。尤其是對于執行效率要求高的程序更應如此。因為使用數組(Array)避免了同步、額外的方法調用和不必要的重新分配空間的操作。
總結
如果涉及到堆棧、隊列等操作,應該考慮用List;
對于需要快速插入,刪除元素,應該使用LinkedList;
如果需要快速隨機訪問元素,應該使用ArrayList。
如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,
如果多個線程可能同時操作一個類,應該使用同步的類。
盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變,這就是針對抽象編程。
參考推薦:
ARRAYLIST VECTOR LINKEDLIST區別
ArrayList、LinkedList、Vector的關系和區別
Java 集合類Array、List、Map區別和聯系
C++ hash_map 與 Java HashMap 的區別
Java util之常用數據類型特性盤點?(推薦)
cplusplus.com
from:?http://blog.csdn.net/ithomer/article/details/7667364
總結
以上是生活随笔為你收集整理的ArrayList、LinkedList、 Vector、Map 用法比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM 优点与缺点的深入分析
- 下一篇: Java 10个调试技巧