1. 程式人生 > >JAVA集合的相關知識

JAVA集合的相關知識

什麼是集合

集合是JAVA存放資料容器,集合類存放於java.util包中。
集合類存放的都是物件的引用,而非物件本身,出於表達上的便利,我們稱集合中的物件就是指集合中物件的引用(reference)

集合有哪些

集合框架示意圖!
集合

按照儲存的方式主要分為兩大類Map(存鍵值對),collection(存單個元素)。
collection:有三個介面list、set、queue

Iterable

集合的根介面(map除外)

public interface Iterable<T> {
    Iterator<T> iterator();
}

iterator是集合的迭代器,用於遍歷集合的元素。
主要hashNext(),next(),remove()三種方法,ListIterator繼承於Iterable新增了add(),previous(),hasPrevious()方法。

Collection

List 介面和 Set 介面的父介面

public interface Collection<E> extends Iterable<E> {
}

在這裡插入圖片描述

List

有序,可以重複的集合。 繼承collection所以他有collection中的方法
在這裡插入圖片描述

list 的實現類有 ArrayList、LinkedList、Vetor

①、List list1 = new ArrayList();
    底層資料結構是陣列,查詢快,增刪慢;執行緒不安全,效率高
②、List list2 = new Vector();
   底層資料結構是陣列,查詢快,增刪慢;執行緒安全(synchronized),效率低,幾乎已經淘汰了這個集合,子類stack
③、List list3 = new LinkedList();
   底層資料結構是連結串列,查詢慢,增刪快;執行緒不安全,效率高

Set

無序、不可重複的集合,具體實現類hashSet(LinkedHashSet)、SortedSet(TreeSet)
在這裡插入圖片描述

SET

①、Set hashSet = new HashSet();
   HashSet:不能保證元素的順序;不可重複;不是執行緒安全的;集合元素可以為 NULL,底層採用hash表的演算法;
②、Set linkedHashSet = new LinkedHashSet();
   因為底層採用 連結串列 和 雜湊表的演算法。連結串列保證元素的新增順序,雜湊表保證元素的唯一性
③、Set treeSet = new TreeSet();
   TreeSet:有序;不可重複,底層使用 紅黑樹演算法,擅長於範圍查詢。

Map

key-value 的鍵值對,key 不允許重複,value 可以重複
因為 Map 集合即沒有實現於 Collection 介面,也沒有實現 Iterable 介面,所以不能對 Map 集合進行 for-each 遍歷。

遍歷map
map中 interface Entry<K,V> 屬性。

 HashMap< String, String> map =  new HashMap<String, String>();
 		//先獲取key的Set,再通過key獲取value
   		for (String key : map.keySet()) {
   			map.get(key);
   		}
   		// 將map的entry作為值放入set中,遍歷entry
 		for (Map.Entry<String, String> entry : map.entrySet()) {
 			   entry.getKey();
 			   entry.getValue();
 			}
  }  

MAP的子類
HashMap,HashTable,LinkedHashMap,TreeMap

集合的面試問題

點這裡

  • 1 泛型的作用
    Java1.5引入了泛型,所有的集合介面和實現都大量地使用它。泛型允許我們為集合提供一個可以容納的物件型別,因此,如果你新增其它型別的任何元素,它會在編譯時報錯。這避免了在執行時出現ClassCastException,因為你將會在編譯時得到報錯資訊。泛型也使得程式碼整潔,我們不需要使用顯式轉換和instanceOf操作符。它也給執行時帶來好處,因為不會產生型別檢查的位元組碼指令。

  • 2 集合中那些實現類是執行緒安全的
    Vector 使用synchronized
    Stack 繼承Vector 所以也是執行緒安全的
    Hashtable
    ConcurrentHashMap
    Enumeration

  • Arraylist 與 LinkedList 、Vector區別
    講清楚arraylistlinkedlist的區別,得先從陣列與連結串列講起
    陣列是將元素在記憶體中連續存放,由於每個元素佔用記憶體相同,所以你可以通過下標迅速訪問陣列中任何元素。但是如果你要在陣列中增加一個元素,你需要移動大量元素,在記憶體中空出一個元素的空間,然後將要增加的元素放在其中。同樣的道理,如果你想刪除一個元素,你同樣需要移動大量元素去填掉被移動的元素。
    連結串列中的元素在記憶體中不是順序儲存的,而是通過存在元素中的指標聯絡到一起。比如:上一個元素有個指標指到下一個元素,以此類推,直到最後一個元素。如果你要訪問連結串列中一個元素,你需要從第一個元素開始,一直找到你需要的元素位置。但是增加和刪除一個元素對於連結串列資料結構就非常簡單了, 只要修改元素中的指標就可以了。

綜上可以得出,基於陣列實現的arraylist在查詢上比較方便,而增刪上比較慢。而基於連結串列實現的linkedlist在查詢上比較慢需要從頭開始搜尋,而在元素增刪的操作上比較快。

Vector底層與arraylist相似,但是其方法上有synchronized 以實現執行緒同步,所以在效率上比arraylist要低,但是執行緒安全。

  • HashMap 和 Hashtable 的區別
    點這裡
    在使用HashMap和Hashtable時要先了解其實現原理,下面會介紹,這裡只講區別
    1、 Hashtable在其方法上加上了synchronized 使得其在多執行緒中是安全的,而HashMap是非synchronized的。
    我們能否讓HashMap同步?
    Map m = Collections.synchronizeMap(hashMap);
    2 、 HashMap可以有空鍵值對,但是Hashtable不可以有空鍵值對
	HashMap< String, String> map =  new HashMap<String, String>();
  		 map.put(null, null);
   Hashtable<String, String> tHashtable = new Hashtable<String, String>();
   try {
	 	  tHashtable.put(null, "");
	} catch (NullPointerException e) {
		System.err.println( "Hashtable 不允許空鍵值對");
	}

結果:
在這裡插入圖片描述

  • comparable 和 comparator的區別?
    HashMap 的工作原理及程式碼實現
    我們都知道map裡元素是以鍵值對Entry<key,value>儲存的,那我們具體怎麼將Entry放入到bucket中呢
    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

我們先通過key計算出hash值 int hash = hash(key);,然後通過hash和length獲取bucket的索引值
Entry<K,V> e = table[i]; e != null; e = e.next,獲取索引i的元素entry,如果entry有值就next,直到key與e.key相等位置。然後把value值替換。

我們再來看get方法

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);
        return null == entry ? null : entry.getValue();
    }

如果key為null則返回null,
getEntry(key) 如果indexFor(hash, table.length)索引沒有找到,則返回null,如果有值則把key相等的value返回。

ConcurrentHashMap 的工作原理及程式碼實現
我們都知道hashmap是不安全的,而hashtable效率低
concurrenthashmap是執行緒安全又效率較高的一種選擇。
ConcurrentHashMap所使用的是鎖分段技術,首先將資料分成一段一段的儲存,然後給每一段資料配一把鎖,當一個執行緒佔用鎖訪問其中一個段資料的時候,其他段的資料也能被其他執行緒訪問。


上述內容是本人通過對其他優秀部落格的整理,為自己對此部分的知識進行梳理,如有錯誤請指出,本人其他部落格也會以此形式整理(自己理解+原文部落格連結)。