Java之Collection/Map

 

Java中容器分兩類,一種是單值的Collection,一種是儲存鍵-值對的Mapjava

 

Collection算法

又分兩種,Set和List,區別在於Set是不可重複的,而List是可重複的數組

Setpost

經常使用有兩種:HashSetTreeSet,其內部實現是一個Map,它的元素就至關於Map中的Key,而Value是一個Object常量this

 

       
private transient HashMap<E,Object> map;
ivate static final Object PRESENT = new Object();
p r public HashSet() {
p<E,Object>(); }
map = new HashM
a



 

       
private transient NavigableMap<E,Object> m;
ivate static final Object PRESENT = new Object();
p r public TreeSet() {
ap<E,Object>()); }
this ( new Tree
M


全部對Set的操做都被最終轉嫁爲對Map的操做,具體細節在下面Map中講述編碼

 

Listspa

對Collection接口進行了簡單的擴充,你能夠將任何對象放到放到一個List容器中,並在須要時從中取出。code

經常使用的有ArrayList和LinkedList,都是有順序,可重複的集合類型orm

 

ArrayList:顧名思義,數據列表,其實就是封裝了一個數組,所以它的訪問速度極快對象


       
private transient Object[] elementData;
ivate int size;
p r


而後封裝了一些對數組的經常使用操做如插入、刪除等。

 

說到ArrayList不得不提下Arrays類和數組[]

 

ArrayList能夠儲存不一樣類型的對象(雖然通常不推薦這樣作),而數組只能是同一類型

ArrayList能夠動態增長長度,但效率不高,而數組只能是固定長度,卻十分高效。每當執行add/insert等添加元素的方法,都會先檢查數組長度是否足夠,若是是,它就會以當前容量的3/2倍+1來從新構建一個數組,將舊元素Copy到新數組中,而後丟棄舊數組,在這個臨界點的擴容操做,應該來講是比較影響效率的。

ArrayList提供經常使用方法,add/get/indexOf/remove等,而相應的Arrays沒有提供add和remove方法,查詢元素索引要先sort再binarySearch

ArrayList排序需外部方法Collections.sort(..),數組排序則使用Arrays.sort(..),兩者均可以使用天然順序(實現Comparable)或用Comparator指定

 

LinkedList:很顯然的是鏈表,內部實現是帶頭結點的雙向鏈表,適合於在鏈表中間須要頻繁進行插入和刪除操做

 

 

       
private transient Entry<E> header = new Entry<E>( null , null , null );
private transient int size = 0 ; private static class Entry<E> {
E element; Entry<E> next; Entry<E> previous; //..
}


 

 

Map

是一種把鍵和值對象進行關聯的容器,類比Collection,能夠這樣說:Collection對象中某個值的ID是它在容器中的索引值,而在Map中,某個值的ID是它對應的鍵。這樣咱們使用Map時就不用侷限於int型的索引值,能夠用任何類型的對象做索引。正是因爲Key的索引特性,Map中不容許有同值的Key存在(前文講到Set內部實現是Map中的Key的集合,因此Set的元素不能重複)。固然,Value是能夠重複的,甚至能夠是同一個Reference。Map在處理相同的Key時,將新值存入,舊值被替換並返回

 

HashMap採用Hash算法,以便快速查找某個元素。

將鍵的哈希值做爲內存索引依據,內部實現是一個適當長度的鏈式數組,由Key的Hash值對應數組下標,再間接對應內存,是一種比較高效的存取方式。Key的hashCode()相同的狀況下,放在同一個單項鍊表結構中。

一個HashMap中Key的類型應該重寫hashCode()方法,保證在兩個對象equals爲true時返回相同的值,不然在重複性檢查時會直接被當作不一樣的鍵,形成不可預期的後果。

Hash容器中判斷重複的方式:

先比較hash(key.hashCode())是否相同,hash(int)是一個內部算法,具體細節不做討論

  不一樣,則不重複

  相同,則

    比較兩個Key是不是同一引用

      是,則重複

      不是,再調用equals方法

        返回true則重複

        返回false則不重複

TreeMap:採用樹型儲存結構按序存放,所以它便有一些擴展的方法,好比firstKey(),lastKey()等,你還能夠從TreeMap中指定一個範圍以取得其子Map。

內部實現是一顆二叉排序樹,其中序遍歷結果爲遞增序列。因此要求他的Key必須是Comparable或者建立TreeMap的時候指定Comparator。

當Key實現Comparable<E>接口時,必須實現comparaTo(E e)方法,當使用外部比較器(Comparator<T>)時,需實現Comparator<T>的compare(T t1, T t2)方法

 

相關知識

 

泛型(Generic)

泛型容許Coding的時候能夠定義一些可變的類型,但必須在使用前進行聲明具體是哪一種類型

 

       
class testGeneric<T> {
T t;
eneric(T t) {
test Gthis .t = t; } }
eric<String>
class test { testGe
n tgs = new testGeneric( "Hi,Gineric!" );
testGeneric<Integer> tgi = new testGeneric( 100 ); //AutoBoxing
{ System.out.println(tgs.t); //Output:Hi,Gineric!
} }
System.out.println(tgi.t); //AutoUnBoxing&Output:100


須要注意Java 泛型的類型參數之實際類型在編譯時會被消除(upcast to Object),因此沒法在運行時得知其類型參數的類型。Java 編譯器在編譯泛型時會自動加入類型轉換的編碼,故運行速度不會由於使用泛型而加快。

 

迭代器(Iterator)

提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。

對於遍歷一個容器中全部的元素,Iterator模式是首選的方式

Collection定義了Iterator<E> iterator()方法,子類都各自實現了該方法,咱們直接調用便可

Map中雖沒有定義,咱們能夠利用map.entrySet()的iterator()方法

 

 

       
Iterator i = someMap.entrySet().iterator();
while (i.hasNext()) {
(Map.Entry) i.next(); Object key = i.g
Map.Entry entry =etKey(); Object value = i.getValue(); //something TODO
}


或者轉換爲Collection(Set)用加強For循環

 

 

       
Set<Map.Entry> entrySet = someMap.entrySet();
for (Map.Entry entry : entrySet){
Object value = entry.getValu
Object key = entry.getKey(); e(); //something TODO
}


 

ListIterator繼承了Iterator,提供了對List的雙向遍歷的方法。

須要注意的是,調用Iterator的remove方法,刪除的是最後一次調用next()(or previous(),if possible)所返回的元素

若是進行迭代時用調用此方法以外的其餘方式修改了該迭代器所指向的 collection,則迭代器的行爲是不肯定的。

也就是說,調用Iterator時,最好不要調用Collection的add/remove等方法

另:容器類的toString()方法也是經過調用iterator()方法來實現遍歷

  對集合使用加強的for循環也是隱式地調用iterator()方法

 

還有Stack、Queue等結構,操做簡單,不做贅述

相關文章
相關標籤/搜索