java中List、Set、Map詳細解析

一.概括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的位置。
  • 結構如圖所示:

圖源見水印。

 

 

 

 

 

發佈了6 篇原創文章 · 獲贊 2 · 訪問量 1401
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章