集合類小結

1、數組與集合java

  數組(能夠存儲對象包括基本類型)是一種常見的數據結構,對元素訪問快速,但長度固定,存儲數據類型需一致。數組

  集合只能存儲對象,長度可變,能夠存儲不一樣類型的對象。安全

  數組與集合之間能夠經過toArray()和Arrays.asList()相互轉換。注:(asList返回的對象是一個Arrays內部類,並無實現集合的add/remove/clear方法。)數據結構

 

2、集合框架圖併發

  集合類存放在java.util包中,主要兩種類型:Collection和Map,繼承關係以下圖:app

 

 

List、Set和Map是集合中的三個主要接口。其中,List和Set繼承自Collection(沒有直接實現類)根接口,Map和Collection相互獨立,但也屬於集合類。
框架

  List:有序且容許元素重複;基於數組的Vector和ArrayList適合查詢,而基於鏈表的LinkedList適合添加,刪除操做。異步

  Set:無序且不容許元素重複;不能重複的緣由是:Set實現的基礎是Map(HashMap),HashMap的key不能重複。this

  Map:鍵值對集合,鍵不能重複,值可重複。spa

 

3、集合類遍歷

一、Collection

Collection沒有get()方法來獲取某個元素,只能經過iterator()遍歷元素;foreach內部也是採用了Iterator的方式實現(循環體remove/add會致使expectedModCount和modCount不相等報異常);List能夠經過get()方法獲取元素,ListIterator是Iterator的子接口,專門用於List。

//iterator
Iterator iterator = list.iterator(); 
while(iterator.hasNext()){ 
  int i = (Integer) iterator.next();                   
  System.out.println(i);   
}

//foreach
for (Object object : list) {  
  System.out.println(object);      
}

//for
for (int i = 0 ;i<list.size();i++) {      
  int v= (Integer) list.get(i);                     
  System.out.println(v);         
} 
    

二、Map

1)經過Map.keySet()將Map中的全部key存入到Set集合中,而後經過iterator()獲取迭代器或者foreach遍歷key,最後經過Map.get(key)方法取得對應的值。

//iterator
Iterator it=map.keySet().iterator(); 
while(it.hasNext()){ 
    String key; 
    String value; 
    key=it.next().toString(); 
    value=map.get(key); 
    System.out.println(key+"--"+value); 
} 

//foreach
for (String key : map.keySet()) {
  System.out.println("key= " + key + " and value= " + map.get(key));
}

2)經過Map.entrySet()將鍵值對做爲一個總體一對一對地存放到Set集合中,Map.Entry表示映射關係,而後經過iterator()獲取迭代器或者foreach遍歷獲取鍵(e.getKey())和值(e.getValue());

//iterator
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
     Map.Entry<Integer, String> entry = it.next();
     System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

//foreach
for (Map.Entry<Integer, String> entry : map.entrySet()) {
    System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

3)經過Map.values()遍歷全部的value,但不能遍歷key。

for (String v : map.values()) {
    System.out.println("value= " + v);
}

 

4、接口實現類的區別比較

一、ArrayList和Vector

1)同步性:Vector使用了synchronized方法,是同步和線程安全的,ArrayList是異步和線程非安全的,能夠經過List Collections.synchronizedList(List list)實現同步。

2)數據增加:當元素個數超過容量時,Vector默認增加爲原來的2倍,ArrayList爲1.5倍;ArrayList與Vector均可以設置初始的空間大小,Vector還能夠設置增加的空間大小,而ArrayList沒有提供設置增加空間的方法。

 二、ArrayList和LinkedList

1)實現基礎:ArrayList基於數組,LinkedList基於雙向鏈表。

2)效率:get和set操做,ArrayList佔優;add和remove操做LinkedList佔優。

三、HashMap和Hashtable

1)繼承:HashMap繼承於AbstractMap,Hashtable繼承於Dictionary。

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable

2)同步性:Hashtable是同步的;HashMap是非同步的,能夠經過Map Collections.synchronizedMap(Map m)實現;如需線程安全,推薦使用ConcurrentHashMap。

3)鍵值要求:HashMap容許存在一個爲null的key,多個爲null的value ;Hashtable的key和value都不容許爲null。

4)遍歷方式內部實現:Hashtable、HashMap都使用了 Iterator;因爲歷史緣由,Hashtable還使用了Enumeration的方式 。

5)默認大小和擴容方式:Hashtable中hash數組默認大小是11,增長的方式是 old*2+1。HashMap中hash數組的默認大小是16,並且必定是2的指數。

jdk1.7
java.util.HashTable
// 哈希表默認初始大小爲11
public Hashtable() {
    this(11, 0.75f);
}

protected void rehash() {
    int oldCapacity = table.length;
    Entry<K,V>[] oldMap = table;

    // 每次擴容爲原來的2n+1
    int newCapacity = (oldCapacity << 1) + 1;
    // ...
}


java.util.HashMap
// 哈希表默認初始大小爲2^4=16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

void addEntry(int hash, K key, V value, int bucketIndex) {
    // 每次擴充爲原來的2n 
    if ((size >= threshold) && (null != table[bucketIndex])) {
       resize(2 * table.length);
}

6)Hashtable直接使用對象的hashCode,而HashMap從新計算hash值

jdk1.7
java.util.HashTable
// hash 不能超過Integer.MAX_VALUE 因此要取其最小的31個bit int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; // 直接計算key.hashCode() private int hash(Object k) { // hashSeed will be zero if alternative hashing is disabled. return hashSeed ^ k.hashCode(); } java.util.HashMap int hash = hash(key); int i = indexFor(hash, table.length); // 在計算了key.hashCode()以後,作了一些位運算來減小哈希衝突 final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } // 取模再也不須要作除法 static int indexFor(int h, int length) { // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; return h & (length-1); }

JDK7中HashMap採用的是位桶+鏈表的方式,即咱們常說的散列鏈表的方式,而JDK8中採用的是位桶+鏈表/紅黑樹(有關紅黑樹請查看紅黑樹)的方式。當某個位桶的鏈表的長度達到某個閥值(8)的時候,這個鏈表就將轉換成紅黑樹,改進鏈表過長查詢慢的問題。另外,JDK8將鏈表頭插改成尾插,避免併發死循環問題,固然仍然是非線程安全,好比數據丟失。

7)Hashtable有一個contains(Object value),功能和containsValue(Object value)功能同樣。

相關文章
相關標籤/搜索