1、java集合:java集合詳解及類關系圖


List和Set繼承自Collection接口。
Set無序不允許元素重復。HashSet和TreeSet是兩個主要的實現類。
List有序且允許元素重復,支持null對象。ArrayList、LinkedList和Vector是三個主要的實現類。

Map也屬於集合系統,但和Collection接口沒關系。Map是key對value的映射集合,其中key列就是一個集合。key不能重復,但是value可以重復。HashMap、TreeMap和Hashtable是三個主要的實現類。

 SortedSet和SortedMap接口對元素按指定規則排序,SortedMap是對key列進行排序。

ArrayList和vector區別

ArrayList和Vector都實現了List接口,都是通過數組實現的。
Vector是線程安全的,而ArrayList是非線程安全的。
List第一次創建的時候,會有一個初始大小,隨着不斷向List中增加元素,當List 認為容量不夠的時候就會進行擴容。Vector缺省情況下自動增長原來一倍的數組長度,ArrayList增長原來的50%。

ArrayList和LinkedList區別及使用場景

  1. 區別

ArrayList底層是用數組實現的,第一次add操作將數組的長度初始化為10,可以認為ArrayList是一個可改變大小的數組。隨着越來越多的元素被添加到ArrayList中,其規模是動態增加的,原理數組大小的1.5倍。
LinkedList底層是通過雙向鏈表實現的,每個節點Node對象包括指向上一個Node對象和指向下一個Node對象,同時LinkedList還實現了Queue接口,所以他還提供了offer(),peek(), poll()等方法。
LinkedList和ArrayList相比,增刪的速度較快。但是查詢和修改值的速度較慢。同時,

2.使用場景

LinkedList更適合從中間插入或者刪除(鏈表的特性)。
ArrayList更適合檢索和在末尾插入或刪除(數組的特性)。

HashTable實現原理

(1)是一個線程安全的散列表,存儲內容是鍵值對映射,不支持和null鍵值對

(2)繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口

(3)線程安全,默認數組長度為11,負載因子為0.75,擴容方式是old*2+1;

具體原理參考文章:http://www.cnblogs.com/skywang12345/p/3310887.html

HashMap和HashTable區別

1).HashTable的方法前面都有synchronized來同步,是線程安全的;HashMap未經同步,是非線程安全的。
2).HashTable不允許null值(key和value都不可以) ;HashMap允許null值(key和value都可以)。
3).HashTable有一個contains(Object value)功能和containsValue(Object value)功能一樣。
4).HashTable使用Enumeration進行遍歷;HashMap使用Iterator進行遍歷。
5).HashTable中hash數組默認大小是11,增加的方式是old*2+1;HashMap中hash數組的默認大小是16,而且一定是2的指數。
6).哈希值的使用不同,HashTable直接使用對象的hashCode; HashMap重新計算hash值,而且用與代替求模。

HashMap實現原理

(1)基於Hash的map接口非同步實現, 無序且允許null的鍵值對。

(2)初始大小為16,默認負載因子0.75。當一個map填滿了75%的bucket時候,將會創建原來HashMap大小的2倍的bucket數組,來重新調整map的大小,並將原來的對象放入新的bucket數組中

(3) put(K key, V value)

     根據key的hashCode值重新計算出hash值(高位計算一次散列,防止低位不變高位變化造成沖突),既而得到這個元素在數組中的位置(下標)如果數組該位置上已經存放有其他元素了,那么在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果數組該位置上沒有元素,就直接將該元素放到此數組中的該位置上。

(4) get(Object key)

計算key的hashCode,找到數組中對應位置的某一元素,然后通過key的equals方法在對應位置的鏈表中找到需要的元素。

(5) 重新調整HashMap大小存在什么問題嗎?

重新調整hashMap大小,確實存在競爭,多線程環境,調整大小的過程中,存儲在LinkedList中的元素的次序會反過來,因為移動到新的bucket位置的時候,HashMap並不會將元素放在LinkedList的尾部,而是放在頭部,這是為了避免尾部遍歷(tail traversing)。如果條件競爭發生了,那么就死循環了。

JDK7 與 JDK8 中關於HashMap的對比

結構不同:

JDK7 HashMap結構為 數組+鏈表 的形式。 JDK8 HashMap結構為 數組+鏈表+紅黑樹 的形式,當桶內元素大於8時,便會樹化。

hash值的計算方式不同

JDK7 table在創建hashmap時分配空間。 JDK8 在put的時候分配,如果table為空,則為table分配空間。

發生沖突時:

插入鏈表操,JDK7是頭插法,JDK8是尾插法。

resize操作:

JDK7 需要重新進行index的計算。 JDK8 不需要,通過判斷相應的位是0還是1,要么依舊是原index,要么是oldCap + 原index。

JDK7 與 JDK8 中關於ConcurrentHashMap的對比

結構不同:

JDK1.7 由Segment數組結構和HashEntry數組結構組成。Segment實際繼承自可重入鎖(ReentrantLock) JDK1.8 直接用Node數組+鏈表+紅黑樹的數據結構來實現,並發控制使用Synchronized和CAS來操作,整個看起來就像是優化過且線程安全的HashMap 

鎖的粒度不同:

JDK1.7 版本鎖的粒度是基於Segment的,包含多個HashEntry,有上限 JDK1.8 的實現降低鎖的粒度,鎖的粒度就是HashEntry(首節點) 

鎖的替代:

JDK1.8為什么使用內置鎖synchronized來代替重入鎖ReentrantLock

因為粒度降低了,在相對而言的低粒度加鎖方式,synchronized並不比ReentrantLock差,在粗粒度加鎖中ReentrantLock可能通過Condition來控制各個低粒度的邊界,更加的靈活,而在低粒度中,Condition的優勢就沒有了 基於JVMsynchronized優化空間更大,使用內嵌的關鍵字比使用API更加自然 

size操作:

JDK7 先進行兩次無鎖統計,相同直接返回,不同再進行加鎖統計 JDK8 擴容和addCount()方法就已經有處理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM