Java中的Map List Set等集合類

Map List Set等集合類:
java

1、概述

在JAVA的util包中有兩個全部集合的父接口Collection和Map,它們的父子關係:web


+Collection 這個接口extends自 --java.lang.Iterable接口
 ├+List(接口 表明有序,可重複的集合。列表)
 │├ ArreyList     (Class 數組,隨機訪問,沒有同步,線程不安全)
 │├ Vector        (Class  數組                   同步        線程全)
 │├ LinkedList    (Class  鏈表   插入刪除   沒有同步   線程不安全)
 │└ Stack          (Class)
 +Set(接口 不能含重複的元素。僅接收一次並作內部排序,集)
 │├ HashSet            (Class)
 │├ LinkedHashSet   (Class)
 │└ TreeSet       (Class)
算法

+Map(接口)
 ├ +Map(接口 映射集合)
 │ ├ HashMap            (Class 不一樣步,線程不安全。除了不一樣和容許使用null 鍵值以外,與Hashtable大體相同)
 │ ├ Hashtable           (Class 同步   ,線程安全    。不容許實施null 鍵值)
 │ ├ +SortedMap 接口
 │    ├ TreeMap         (Class)
 │ ├ WeakHashMap     (Class)
數組

如下對衆多接口和類的簡單說明:首先不能不先說一下數組(Array)安全

一、效率高,但容量固定且沒法動態改變。array還有一個缺點是,沒法判斷其中實際存有多少元素,length只是告訴咱們array的容量。
二、Java中有一個Arrays類,專門用來操做array。
     arrays中擁有一組static函數,
     equals():比較兩個array是否相等。array擁有相同元素個數,且全部對應元素兩兩相等。
     fill():將值填入array中。
     sort():用來對array進行排序。
     binarySearch():在排好序的array中尋找元素。
     System.arraycopy():array的複製。
數據結構

1、數組Array和集合的區別:函數


1)  數組是大小固定的,而且同一個數組只能存放類型同樣的數據(基本類型/引用類型)
2) JAVA集合能夠存儲和操做數目不固定的一組數據。
性能

3)  若程序時不知道究竟須要多少對象,須要在空間不足時自動擴增容量,則須要使用容器類庫,array不適用。測試

二 set map list的區別  

都是集合接口 spa

  set --其中的值不容許重複,無序的數據結構 
  list   --其中的值容許重複,由於其爲有序的數據結構 
  map--成對的數據結構,健值必須具備惟一性(鍵不能同,不然值替換) 

List 按對象進入的順序保存對象,不作排序或編輯操做。

Set對每一個對象只接受一次,並使用本身內部的排序方法(一般,你只關心某個元素是否屬於Set,而不關心它的順序--不然應該使用List)。

Map一樣對每一個元素保存一份,但這是基於"鍵"的,Map也有內置的排序,於是不關心元素添加的順序。若是添加元素的順序對你很重要,應該使用 LinkedHashSet或者LinkedHashMap.

Collection 是對象集合, Collection 有兩個子接口 List 和 Set

List 能夠經過下標 (1,2..) 來取得值,值能夠重複而 Set 只能經過遊標來取值,而且值是不能重複的
ArrayList , Vector , LinkedList 是 List 的實現類
ArrayList 是線程不安全的, Vector 是線程安全的,這兩個類底層都是由數組實現的
LinkedList 是線程不安全的,底層是由鏈表實現的  


Map 是鍵值對集合
HashTable 和 HashMap 是 Map 的實現類
HashTable 是線程安全的,不能存儲
null
HashMap 不是線程安全的,能夠存儲
null

3、 Collections類和Collection接口

         Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各類集合的搜索、排序、線程安全化等操做。

       Collection是最基本的集合接口,一個Collection表明一組Object,即Collection的元素(Elements)。一些 Collection容許相同的元素而另外一些不行。一些能排序而另外一些不行。Java SDK不提供直接繼承自Collection的 類,Java SDK提供的類都是繼承自Collection的「子接口」如List和Set。

  全部實現 Collection 接口的類都必須提供兩個標準的構造函數:無參數的構造函數用於建立一個空的 Collection ,有一個 Collection 參數的構造函數用於建立一個新的 Collection ,這個新的 Collection 與傳入的 Collection 有相同的元素。後一個構造函數容許用戶複製一個 Collection 。

集合類的遍歷:遍歷通用Collection:

  如何遍歷 Collection 中的每個元素?不論 Collection 的實際類型如何,它都支持一個 iterator() 的方法,該方法返回一個迭代子,使用該迭代子便可逐一訪問 Collection 中每個元素。典型的用法以下:

Iterator it = collection.iterator(); // 得到一個迭代子  
  while(it.hasNext()) {  
   Object obj = it.next(); // 獲得下一個元素  
}

由 Collection 接口派生的兩個接口是 List 和 Set 。 List 按對象進入的順序保存對象,不作排序或編輯操做。 Set 對每一個對象只接受一次,並使用本身內部的排序方法 ( 一般,你只關心某個元素是否屬於 Set, 而不關心它的順序-- 不然應該使用 List) 。

4、 List接口,有序可重複的集合

實際上有兩種List: 一種是基本的ArrayList,其優勢在於隨機訪問元素,另外一種是更強大的LinkedList,它並非爲快速隨機訪問設計的,而是具備一套更通用的方法。 

List : 次序是List最重要的特色:它保證維護元素特定的順序。List爲Collection添加了許多方法,使得可以向List中間插入與移除元素(這隻推薦LinkedList使用。)一個List能夠生成ListIterator,使用它能夠從兩個方向遍歷List,也能夠從List中間插入和移除元素。 

1. ArrayList類

1) ArrayList實現了可變大小的數組。它容許全部元素,包括null。ArrayList沒有同步。
2) size,isEmpty,get,set方法運行時間爲常數。可是add方法開銷爲分攤的常數,添加n個元素須要O(n)的時間。其餘的方法運行時間爲線性。
3) 每一個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小。這個容量可隨着不斷添加新元素而自動增長,可是增加算法 並無定義。當須要插入大量元素時,在插入前能夠調用ensureCapacity方法來增長ArrayList的容量以提升插入效率。
4) 和LinkedList同樣,ArrayList也是非同步的(unsynchronized)。

5) 由數組實現的List。容許對元素進行快速隨機訪問,可是向List中間插入與移除元素的速度很慢。ListIterator只應該用來由後向前遍歷ArrayList,而不是用來插入和移除元素。由於那比LinkedList開銷要大不少。
2. Vector類
  Vector很是相似ArrayList,可是Vector是同步的。由Vector建立的Iterator,雖然和ArrayList建立的Iterator是同一接口,可是,由於Vector是同步的,當一個Iterator被建立並且正在被使用,另外一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,所以必須捕獲該異常。

3. LinkedList類
  LinkedList實現了List接口,容許null元素。此外LinkedList提供額外的get,remove,insert方法在 LinkedList的首部或尾部。以下列方法:addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 這些方法 (沒有在任何接口或基類中定義過)。這些操做使LinkedList可被用做堆棧(stack),隊列(queue)或雙向隊列(deque)。
  注意LinkedList沒有同步方法。若是多個線程同時訪問一個List,則必須本身實現訪問同步。一種解決方法是在建立List時構造一個同步的List:
  List list = Collections.synchronizedList(new LinkedList(...));

4. Stack 類
  Stack繼承自Vector,實現一個後進先出的堆棧。Stack提供5個額外的方法使得Vector得以被看成堆棧使用。基本的push和pop方法,還有peek方法獲得棧頂的元素,empty方法測試堆棧是否爲空,search方法檢測一個元素在堆棧中的位置。Stack剛建立後是空棧。

用法:

package Test;  
  
import java.util.ArrayList;  
import java.util.Iterator;  
import java.util.List;  
public class TestList {  
    public static void main(String dd[]) {  
        // new了一個存儲list  
        List l = new ArrayList();  
        // 由於Collection framework只能存儲對象因此new封裝類  
        l.add(new Integer(1));  
        l.add(new Integer(2));  
        l.add(new Integer(3));  
        l.add(new Integer(4));  
  
        Iterator it = l.iterator();  
        //使用 迭代器(Iterator):  
        // hasNext是取值取的是當前值.他的運算過程是判斷下個是否有值若是有繼續.  
        while (it.hasNext()) {  
            System.out.println("iterator:Element in list is :   " + it.next());  
        }  
        //用for循環和get()方法:  
        for (int i = 0; i < l.size(); i++) {  
            System.out.println("for:Element in list is :   " + l.get(i));  
        }  
    }  
}

LinkedList

package Test;  
  
import java.util.Iterator;  
import java.util.LinkedList;  
  
public class TestLinkedList {  
    public static void main(String arg[]) {  
        LinkedList ll = new LinkedList();// 聲明LinkedList並實例化  
        // 使用add()方法添加元素  
        ll.add("a");  
        ll.add("b");  
        ll.add("c");  
        // 使用Iterator迭代器遍歷出集合的元素並打印  
        Iterator it = ll.iterator();  
        while (it.hasNext()) {  
            System.out.println(it.next());  
        }  
        System.out.println("------------------");  
        // 向鏈表頭和尾分別添加x和z  
        ll.addFirst("z");  
        ll.addLast("x");  
        // 遍歷查看添加後的結果  
        for (Iterator i = ll.iterator(); i.hasNext();) {  
            System.out.println(i.next());  
        }  
    }  
}

ArrayList和LinkedList的區別。

1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。

2.對於隨機訪問get和set,ArrayList以爲優於LinkedList,由於LinkedList要移動指針。

3.對於新增和刪除操做add和remove,LinedList比較佔優點,由於ArrayList要移動數據。

若是熟悉數據結構的同窗,就會一下明白,ArrayList就是線性表的順序表示,LinkedList就是線性表的鏈表表示。

5、 Set接口,表明無序,不可重複的集合

        Set具備與Collection徹底同樣的接口,所以沒有任何額外的功能,不像前面有兩個不一樣的List。實際上Set就是Collection,只是行爲不一樣。(這是繼承與多態思想的典型應用:表現不一樣的行爲。)Set不保存重複的元素(至於如何判斷元素相同則較爲負責) 
Set : 存入Set的每一個元素都必須是惟一的,由於Set不保存重複元素。加入Set的元素必須定義equals()方法以確保對象的惟一性。Set與Collection有徹底同樣的接口。Set接口不保證維護元素的次序。 

1. HashSet 

     爲快速查找設計的Set。存入HashSet的對象必須定義hashCode()。 
2. TreeSet 

     保存次序的Set, 底層爲樹結構。使用它能夠從Set中提取有序的序列。 
3. LinkedHashSet 

     具備HashSet的查詢速度,且內部使用鏈表維護元素的順序(插入的次序)。因而在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。

用法:

Set set=new HashSet();  
    String s1=new String("hello");  
    String s2=s1;  
    String s3=new String("world");  
    set.add(s1);  
    set.add(s2);  
    set.add(s3);  
    System.out.println(set.size());//打印集合中對象的數目 爲 2。  
    Set 的 add()方法是如何判斷對象是否已經存放在集合中?  
    boolean isExists=false;  
    Iterator iterator=set.iterator();  
    while(it.hasNext())  {  
        String oldStr=it.next();  
        if(newStr.equals(oldStr)){  
           isExists=true;  
        }  
    }

6、 Map接口:映射

Map沒有繼承Collection接口, Map 提供 key 到 value 的映射,你能夠經過「鍵」查找「值」。一個 Map 中不能包含相同的 key ,每一個 key 只能映射一個 value 。 Map 接口提供3 種集合的視圖, Map 的內容能夠被看成一組 key 集合,一組 value 集合,或者一組 key-value 映射。

方法 put(Object key, Object value) 添加一個「值」 ( 想要得東西 ) 和與「值」相關聯的「鍵」 (key) ( 使用它來查找 ) 。方法get(Object key) 返回與給定「鍵」相關聯的「值」。能夠用 containsKey() 和 containsValue() 測試 Map 中是否包含某個「鍵」或「值」。 標準的 Java 類庫中包含了幾種不一樣的 Map : HashMap, TreeMap, LinkedHashMap, WeakHashMap, IdentityHashMap 。它們都有一樣的基本接口 Map ,可是行爲、效率、排序策略、保存對象的生命週期和斷定「鍵」等價的策略等各不相同。


Map 一樣對每一個元素保存一份,但這是基於
"" 的, Map 也有內置的排序,於是不關心元素添加的順序。若是添加元素的順序對你很重要,應該使用 LinkedHashSet 或者 LinkedHashMap.

執行效率是 Map 的一個大問題。看看
get() 要作哪些事,就會明白爲何在 ArrayList 中搜索「鍵」是至關慢的。而這正是 HashMap 提升速度的地方。 HashMap 使用了特殊的值,稱爲「散列碼」 (hash code) ,來取代對鍵的緩慢搜索。「散列碼」是「相對惟一」用以表明對象的int 值,它是經過將該對象的某些信息進行轉換而生成的(在下面總結二:須要的注意的地方有更進一步探討)。全部 Java 對象都能產生散列碼,由於 hashCode() 是定義在基類 Object 中的方法 。 HashMap 就是使用對象的 hashCode() 進行快速查詢的。此方法可以顯著提升性能。

1.  Hashtable類
  Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象均可做爲key或者value。Hashtable是同步的。

  添加數據使用 put(key, value) ,取出數據使用get(key) ,這兩個基本操做的時間開銷爲常數。
Hashtable 經過初始化容量 (initial capacity) 和負載因子 (load factor) 兩個參數調整性能。一般缺省的 load factor
0.75 較好地實現了時間和空間的均衡。增大 load factor 能夠節省空間但相應的查找時間將增大,這會影響像get 和 put 這樣的操做。
使用 Hashtable 的簡單示例以下,將
123 放到 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 是同步的。

2.  HashMap類
  HashMap和Hashtable相似,也是基於hash散列表的實現。不一樣之處在於 HashMap是非同步的,而且容許null,即null value和null key。,可是將HashMap視爲Collection時 (values()方法可返回Collection),其迭代子操做時間開銷和HashMap的容量成比例。所以,若是迭代操做的性能至關重要的話,不要 將HashMap的初始化容量設得太高,或者load factor太低。

   LinkedHashMap 類:相似於 HashMap ,可是迭代遍歷它時,取得「鍵值對」的順序是其插入次序,或者是最近最少使用 (LRU) 的次序。只比 HashMap 慢一點。而在迭代訪問時發而更快,由於它使用鏈表維護內部次序。
3.  WeakHashMap類 (弱鍵( weak key ))
  WeakHashMap是一種改進的HashMap,它是爲解決特殊問題設計的,它對key實行「弱引用」,若是一個key再也不被外部所引用,那麼該key能夠被GC回收。

4. TreeMap 類
基於紅黑樹數據結構的實現。查看「鍵」或「鍵值對」時,它們會被排序 ( 次序由 Comparabel 或 Comparator 決定 ) 。 TreeMap 的特色在於,你獲得的結果是通過排序的。 TreeMap 是惟一的帶有 subMap() 方法的 Map ,它能夠返回一個子樹。

5. IdentifyHashMap 類
使用
== 代替 equals() 對「鍵」做比較的 hash map 。專爲解決特殊問題而設計。

 用法:

1 添加,刪除操做:

Object put(Object key, Object value): 向集合中加入元素  
Object remove(Object key):   刪除與KEY相關的元素  
void putAll(Map t):   未來自特定映像的全部元素添加給該映像  
void clear(): 從映像中刪除全部映射

 2 查詢操做:
    Object get(Object key): 得到與關鍵字key相關的值
    Map集合中的鍵對象不容許重複,也就說,任意兩個鍵對象經過equals()方法比較的結果都是false.
    可是能夠將任意多個鍵獨享映射到同一個值對象上。
    Conllections : 集合實用類
    Conllections提供了供JAVA集合實用的靜態方法

7、 如何選擇

一、容器類和Array的區別、擇取
      1)容器類僅能持有對象引用(指向對象的指針),而不是將對象信息copy一份至數列某位置。
      2)一旦將對象置入容器內,便損失了該對象的型別信息。

二、
     1)  在各類Lists中,最好的作法是以ArrayList做爲缺省選擇。當插入、刪除頻繁時,使用LinkedList();
           Vector老是比ArrayList慢,因此要儘可能避免使用。
      2) 在各類Sets中,HashSet一般優於HashTree(插入、查找)。只有當須要產生一個通過排序的序列,才用TreeSet。
           HashTree存在的惟一理由:可以維護其內元素的排序狀態。
      3) 在各類Maps中,HashMap用於快速查找。
      4)  當元素個數固定,用Array,由於Array效率是最高的。

結論:最經常使用的是ArrayList,HashSet,HashMap,Array。並且,咱們也會發現一個規律,用TreeXXX都是排序的。

注意:

一、Collection沒有get()方法來取得某個元素。只能經過iterator()遍歷元素。
二、Set和Collection擁有如出一轍的接口。
三、List能夠經過get()方法來一次取出一個元素。使用數字來選擇一堆對象中的一個,get(0)...。(add/get)
四、通常使用ArrayList。用LinkedList構造堆棧stack、隊列queue

五、Map用 put(k,v) / get(k),還可使用containsKey()/containsValue()來檢查其中是否含有某個key/value。
      HashMap會利用對象的hashCode來快速找到key。
    *     hashing
          哈希碼就是將對象的信息通過一些轉變造成一個獨一無二的int值,這個值存儲在一個array中。
          咱們都知道全部存儲結構中,array查找速度是最快的。因此,能夠加速查找。
      
          發生碰撞時,讓array指向多個values。即,數組每一個位置上又生成一個槤表。

六、Map中元素,能夠將key序列、value序列單獨抽取出來。
使用keySet()抽取key序列,將map中的全部keys生成一個Set。
使用values()抽取value序列,將map中的全部values生成一個Collection。

爲何一個生成Set,一個生成Collection?那是由於,key老是獨一無二的,value容許重複。

相關文章
相關標籤/搜索