天天看點

Set,List,Map的關系 Set,List,Map的差別

java集合的主要分為三種類型:

set(集)

list(清單)

map(映射)

要深入了解集合首先要了解下我們熟悉的數組:

數組是大小固定的,并且同一個數組隻能存放類型一樣的資料(基本類型/引用類型),而java集合可以存儲和操作數目不固定的一組資料。 所有的java集合都位于 java.util包中! java集合隻能存放引用類型的的資料,不能存放基本資料類型。

簡單說下集合和數組的差別:(參考文章:《thinking in algorithm》03.資料結構之數組)

[html]

view plaincopyprint?

Set,List,Map的關系 Set,List,Map的差別
Set,List,Map的關系 Set,List,Map的差別

<span style="font-family:microsoft yahei;font-size:12px;">世間上本來沒有集合,(隻有數組參考c語言)但有人想要,是以有了集合  

有人想有可以自動擴充的數組,是以有了list  

有的人想有沒有重複的數組,是以有了set  

有人想有自動排序的組數,是以有了treeset,treelist,tree**  

而幾乎有有的集合都是基于數組來實作的.  

因為集合是對數組做的封裝,是以,數組永遠比任何一個集合要快  

但任何一個集合,比數組提供的功能要多  

一:數組聲明了它容納的元素的類型,而集合不聲明。這是由于集合以object形式來存儲它們的元素。  

二:一個數組執行個體具有固定的大小,不能伸縮。集合則可根據需要動态改變大小。  

三:數組是一種可讀/可寫資料結構---沒有辦法建立一個隻讀數組。然而可以使用集合提供的readonly方法,以隻讀方式來使用集合。該方法将傳回一個集合的隻讀版本。</span>  

java所有“存儲及随機通路一連串對象”的做法,array是最有效率的一種。

1、

效率高,但容量固定且無法動态改變。

array還有一個缺點是,無法判斷其中實際存有多少元素,length隻是告訴我們array的容量。

2、java中有一個arrays類,專門用來操作array。

     arrays中擁有一組static函數,

equals():比較兩個array是否相等。array擁有相同元素個數,且所有對應元素兩兩相等。

fill():将值填入array中。

sort():用來對array進行排序。

binarysearch():在排好序的array中尋找元素。

system.arraycopy():array的複制。

若撰寫程式時不知道究竟需要多少對象,需要在空間不足時自動擴增容量,則需要使用容器類庫,array不适用。是以就要用到集合。

那我們開始讨論java中的集合。

集合分類:

collection:list、set

map:hashmap、hashtable

collection是最基本的集合接口,聲明了适用于java集合(隻包括set和list)的通用方法。 set 和list 都繼承了conllection,map。

Set,List,Map的關系 Set,List,Map的差別
Set,List,Map的關系 Set,List,Map的差別

<span style="font-weight: normal;">boolean add(object o)      :向集合中加入一個對象的引用   

void clear():删除集合中所有的對象,即不再持有這些對象的引用   

boolean isempty()    :判斷集合是否為空   

boolean contains(object o) : 判斷集合中是否持有特定對象的引用   

iterartor iterator()  :傳回一個iterator對象,可以用來周遊集合中的元素   

boolean remove(object o) :從集合中删除一個對象的引用   

int size()       :傳回集合中元素的數目   

object[] toarray()    : 傳回一個數組,該數組中包括集合中的所有元素 </span>  

關于:iterator() 和toarray() 方法都用于集合的所有的元素,前者傳回一個iterator對象,後者傳回一個包含集合中所有元素的數組。

Set,List,Map的關系 Set,List,Map的差別
Set,List,Map的關系 Set,List,Map的差別

hasnext():判斷集合中元素是否周遊完畢,如果沒有,就傳回true   

next() :傳回下一個元素   

remove():從集合中删除上一個有next()方法傳回的元素。  

set是最簡單的一種集合。集合中的對象不按特定的方式排序,并且沒有重複對象。 set接口主要實作了兩個實作類:

hashset: hashset類按照雜湊演算法來存取集合中的對象,存取速度比較快 

treeset :treeset類實作了sortedset接口,能夠對集合中的對象進行排序。 

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;  

}  

set的功能方法 

set具有與collection完全一樣的接口,是以沒有任何額外的功能,不像前面有兩個不同的list。實際上set就是collection,隻 是行為不同。(這是繼承與多态思想的典型應用:表現不同的行為。)set不儲存重複的元素(至于如何判斷元素相同則較為負責) 

set : 存入set的每個元素都必須是唯一的,因為set不儲存重複元素。加入set的元素必須定義equals()方法以確定對象的唯一性。set與collection有完全一樣的接口。set接口不保證維護元素的次序。 

hashset:為快速查找設計的set。存入hashset的對象必須定義hashcode()。 

treeset: 儲存次序的set, 底層為樹結構。使用它可以從set中提取有序的序列。 

linkedhashset:具有hashset的查詢速度,且内部使用連結清單維護元素的順序(插入的次序)。于是在使用疊代器周遊set時,結果會按元素插入的次序顯示。

list的特征是其元素以線性方式存儲,集合中可以存放重複對象。 

list接口主要實作類包括:(參考文章:arraylist與linkedlist的差別)

arraylist() : 代表長度可以改變得數組。可以對元素進行随機的通路,向arraylist()中插入與删除元素的速度慢。 

linkedlist(): 在實作中采用連結清單資料結構。插入和删除速度快,通路速度慢。 

對于list的随機通路來說,就是隻随機來檢索位于特定位置的元素。 list 的 get(int index) 方法放回集合中由參數index指定的索引位置的對象,下标從“0” 開始。最基本的兩種檢索集合中的所有對象的方法: 

      1: for循環和get()方法: 

for(int i=0; i<list.size();i++){  

system.out.println(list.get(i));  

2: 使用 疊代器(iterator): 

iterator it=list.iterator();  

while(it.hashnext()){  

system.out.println(it.next());  

list的功能方法 

實際上有兩種list:一種是基本的arraylist,其優點在于随機通路元素,另一種是更強大的linkedlist,它并不是為快速随機通路設計的,而是具有一套更通用的方法。

list:次序是list最重要的特點:它保證維護元素特定的順序。list為collection添加了許多方法,使得能夠向list中間插入與移除元素(這隻推 薦linkedlist使用。)一個list可以生成listiterator,使用它可以從兩個方向周遊list,也可以從list中間插入和移除元 素。 

arraylist:由數組實作的list。允許對元素進行快速随機通路,但是向list中間插入與移除元素的速度很慢。listiterator隻應該用來由後向前周遊 arraylist,而不是用來插入和移除元素。因為那比linkedlist開銷要大很多。 

linkedlist :對順序通路進行了優化,向list中間插入與删除的開銷并不大。随機通路則相對較慢。(使用arraylist代替。)還具有下列方 法:addfirst(), addlast(), getfirst(), getlast(), removefirst() 和 removelast(), 這些方法 (沒有在任何接口或基類中定義過)使得linkedlist可以當作堆棧、隊列和雙向隊列使用。

map 是一種把鍵對象和值對象映射的集合,它的每一個元素都包含一對鍵對象和值對象。 map沒有繼承于collection接口 從map集合中檢索元素時,隻要給出鍵對象,就會傳回對應的值對象。 

map 的常用方法: 

1 添加,删除操作: 

Set,List,Map的關系 Set,List,Map的差別
Set,List,Map的關系 Set,List,Map的差別

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.,但是可以将任意多個鍵獨享映射到同一個值對象上。 

map的功能方法

方法put(object key, object value)添加一個“值”(想要得東西)和與“值”相關聯的“鍵”(key)(使用它來查找)。方法get(object key)傳回與給定“鍵”相關聯的“值”。可以用containskey()和containsvalue()測試map中是否包含某個“鍵”或“值”。 标準的java類庫中包含了幾種不同的map:hashmap, treemap, linkedhashmap,

weakhashmap, identityhashmap。它們都有同樣的基本接口map,但是行為、效率、排序政策、儲存對象的生命周期和判定“鍵”等價的政策等各不相同。 

執行效率是map的一個大問題。看看get()要做哪些事,就會明白為什麼在arraylist中搜尋“鍵”是相當慢的。而這正是hashmap提高速 度的地方。hashmap使用了特殊的值,稱為“散列碼”(hash code),來取代對鍵的緩慢搜尋。“散列碼”是“相對唯一”用以代表對象的int值,它是通過将該對象的某些資訊進行轉換而生成的。所有java對象都 能産生散列碼,因為hashcode()是定義在基類object中的方法。 

hashmap就是使用對象的hashcode()進行快速查詢的。此方法能夠顯着提高性能。 

map : 維護“鍵值對”的關聯性,使你可以通過“鍵”查找“值”

hashmap:map基于散清單的實作。插入和查詢“鍵值對”的開銷是固定的。可以通過構造器設定容量capacity和負載因子load factor,以調整容器的性能。 

linkedhashmap: 類似于hashmap,但是疊代周遊它時,取得“鍵值對”的順序是其插入次序,或者是最近最少使用(lru)的次序。隻比hashmap慢一點。而在疊代通路時發而更快,因為它使用連結清單維護内部次序。 

treemap : 基于紅黑樹資料結構的實作。檢視“鍵”或“鍵值對”時,它們會被排序(次序由comparabel或comparator決定)。treemap的特點在 于,你得到的結果是經過排序的。treemap是唯一的帶有submap()方法的map,它可以傳回一個子樹。 

weakhashmao :弱鍵(weak key)map,map中使用的對象也被允許釋放: 這是為解決特殊問題設計的。如果沒有map之外的引用指向某個“鍵”,則此“鍵”可以被垃圾收集器回收。 

identifyhashmap: : 使用==代替equals()對“鍵”作比較的hash map。專為解決特殊問題而設計。

容器内每個為之所存儲的元素個數不同。

collection類型者,每個位置隻有一個元素。

map類型者,持有 key-value pair,像個小型資料庫。

collection

     --list:将以特定次序存儲元素。是以取出來的順序可能和放入順序不同。

           --arraylist / linkedlist / vector

     --set : 不能含有重複的元素

           --hashset / treeset

      map

     --hashmap

     --hashtable

     --treemap

list,set,map将持有對象一律視為object型别。

collection、list、set、map都是接口,不能執行個體化。

    繼承自它們的 arraylist, vector, hashtable, hashmap是具象class,這些才可被執行個體化。

vector容器确切知道它所持有的對象隸屬什麼型别。vector不進行邊界檢查。

總結

1. 如果涉及到堆棧,隊列等操作,應該考慮用list,對于需要快速插入,删除元素,應該使用linkedlist,如果需要快速随機通路元素,應該使用arraylist。

2. 如果程式在單線程環境中,或者通路僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。

3. 在除需要排序時使用treeset,treemap外,都應使用hashset,hashmap,因為他們 的效率更高。

4. 要特别注意對哈希表的操作,作為key的對象要正确複寫equals和hashcode方法。

5. 容器類僅能持有對象引用(指向對象的指針),而不是将對象資訊copy一份至數列某位置。一旦将對象置入容器内,便損失了該對象的型别資訊。

6. 盡量傳回接口而非實際的類型,如傳回list而非arraylist,這樣如果以後需要将arraylist換成linkedlist時,用戶端代碼不用改變。這就是針對抽象程式設計。

注意:

1、collection沒有get()方法來取得某個元素。隻能通過iterator()周遊元素。

2、set和collection擁有一模一樣的接口。

3、list,可以通過get()方法來一次取出一個元素。使用數字來選擇一堆對象中的一個,get(0)...。(add/get)

4、一般使用arraylist。用linkedlist構造堆棧stack、隊列queue。

5、map用 put(k,v) / get(k),還可以使用containskey()/containsvalue()來檢查其中是否含有某個key/value。

      hashmap會利用對象的hashcode來快速找到key。

6、map中元素,可以将key序列、value序列單獨抽取出來。

使用keyset()抽取key序列,将map中的所有keys生成一個set。

使用values()抽取value序列,将map中的所有values生成一個collection。

為什麼一個生成set,一個生成collection?那是因為,key總是獨一無二的,value允許重複。