一.概括List、Set、Map之間的聯繫和區別:
1.List和Set有相同的父類 Collection;區別是Set中沒有相同的元素,List中可以有相同的元素;
2.map 是獨立的合集 它使用鍵值對(key-value)的方式來儲存數據 ;鍵不能有重複的 值可以用
二.詳細解析
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
|-HashSet
└TreeSet
Map
├Hashtable
├HashMap
└WeakHashMap
1.List
有序的集合。用法上可以代替數組來使用,方便根據index(位置)進行插入和查找。List中可以包含null元素。
|--List:
|-- ArrayList:底層使用的是數組結構;數組長度是可變的:百分之五十延長;特點:查詢很快,但增刪慢;線程不同步
|-- LinkedList:底層是鏈表結構;本質是雙向鏈表;特點;查詢較慢,增刪較快;線程不同步
|-- Vector:底層是數組數據結構 線程同步(數組長度是可變的百分之百延長)(無論查詢還是增刪都很慢,被ArrayList替代了)
1)LinkedList類
- LinkedList實現了List接口、Deque 接口、Cloneable接口、java.io.Serializable接口;LinkedList繼承於AbstractSequentialList;LinkedList提供額外的get,remove,insert方法在 LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
- 注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
List list = Collections.synchronizedList(new LinkedList(…));
2)ArrayList類
相當於動態數組。
- size,isEmpty,get,set方法運行時間爲常數。但是add方法開銷爲分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間爲線性。
- 每個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小。這個容量可隨着不斷添加新元素而自動增加,但是增長算法並 沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
- 特點是:尋址容易,插入和刪除困難;
2.Set
|--Set:
|-- HashSet:底層使用的是數組結構;數組長度是可變的:百分之五十延長;特點:查詢很快,但增刪慢;線程不同步
|-- TreeSet:底層是鏈表結構;本質是雙向鏈表;特點;查詢較慢,增刪較快;線程不同步
3.Map
|--Map:
|-- Hashtable類:
- Hashtable繼承Map接口,實現key-value映射的哈希表。key和value都必須是非空對象。
- 添加數據:put(key, value),取數據:get(key),兩個基本操作的時間開銷都爲常數。
- Hashtable是同步的。
|-- HashMap類:HashMap是異步的,key和value都可以是null。
其迭代子操作時間開銷和HashMap 的容量成比例,因此,不要將HashMap的初始化容量設得過高,或者load factor過低。
|-- WeakHashMap類:WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那麼該key可以被GC回收。
HashMap遍歷常用的方法(性能較高)
方法一:使用Iterator、entryset遍歷
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
該種方式看起來冗餘卻有其優點所在。首先,在老版本java(java1.5以前)中這是惟一遍歷map的方式。另一個好處是,你可以在遍歷時調用iterator.remove()來刪除entries,另一個方法則不能。
方法二:在for-each循環中使用entries來遍歷
這是最常見的並且在大多數情況下也是最可取的遍歷方式。在鍵值都需要時使用。
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
注意:for-each循環在java 5中被引入所以該方法只能應用於java 5或更高的版本中。如果你遍歷的是一個空的map對象,for-each循環將拋出NullPointerException,因此在遍歷前你總是應該檢查空引用。
HashMap數據結構
- HashMap裏面實現一個靜態內部類Entry,其重要的屬性有 key , value, next.
數據 - value的值是元素的key的哈希值對數組長度取模得到。如下面第二幅圖中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存儲在數組下標爲12的位置。
- 結構如圖所示:
圖源見水印。