【学习笔记-集合】HashMap 源码浅析
生活随笔
收集整理的這篇文章主要介紹了
【学习笔记-集合】HashMap 源码浅析
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
/**?* HashMap主要方法解析,jdk1.7版本的HashMap?* HashMap數(shù)據(jù)是通過數(shù)組和鏈表結(jié)合的方式(鏈表散列)存儲。?* 在put時候根據(jù)key值得到hash值(地址)即數(shù)組下標(biāo),之后如果得到相同下標(biāo)則放在鏈表前面,之前的數(shù)據(jù)在鏈表尾部。 ? ? ? ? ? ? ? ? ???* 之前的數(shù)據(jù)在鏈表尾部。 ??* ?在查找數(shù)據(jù)時候根據(jù)hashcode獲取數(shù)組下標(biāo),在鏈表中使用equals根據(jù)key查找value.?* 一、構(gòu)造?* 4個構(gòu)造相對之前的jdk版本功能基本不變,但是代碼封裝更完善。?* 構(gòu)造前一個參數(shù)是容量,相當(dāng)于數(shù)組大小,后一個是負(fù)載因子?*/public HashMap(int initialCapacity, float loadFactor) {? ? ? ? //當(dāng)初始容量<0,拋出異常非法的參數(shù)容量? ? ? ? if (initialCapacity < 0)? ? ? ? ? ? throw new IllegalArgumentException("Illegal initial capacity: " +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?initialCapacity);? ? ? ? //初始容量不能大于最大容量值,最大容量值為MAXIMUM_CAPACITY = 1 << 30;? ?? ? ? ? //左移一位相當(dāng)于乘以2,所以左移30位相當(dāng)于2^30.? ? ? ? if (initialCapacity > MAXIMUM_CAPACITY)? ? ? ? ? ? initialCapacity = MAXIMUM_CAPACITY;? ? ? ? //負(fù)載因子不為空并且<=0? ? ? ? if (loadFactor <= 0 || Float.isNaN(loadFactor))? ? ? ? ? ? throw new IllegalArgumentException("Illegal load factor: " +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?loadFactor);? ? ? ? //保存參數(shù)并且初始化數(shù)組? ? ? ? this.loadFactor = loadFactor;? ? ? ? threshold = initialCapacity;? ? ? ? //此初始化將插入數(shù)據(jù),主要使用Entry? ? ? ? init();? ? }//無參構(gòu)造默認(rèn)容量是16,負(fù)載因子0.75public HashMap() {? ? ? ? this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);? ? }//指定容量參數(shù),默認(rèn)負(fù)載因子0.75public HashMap(int initialCapacity) {? ? ? ? this(initialCapacity, DEFAULT_LOAD_FACTOR);? ? }/構(gòu)造與指定map相同映射的新HashMap?public HashMap(Map<? extends K, ? extends V> m) {? ? ? ? this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,? ? ? ? ? ? ? ? ? ? ? DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);? ? ? ? //如果容量不夠,擴大table數(shù)組? ? ? ? inflateTable(threshold);? ? ? ? //將map中的元素添加到HashMap中? ? ? ? putAllForCreate(m);? ? }?/**?* 二、創(chuàng)建數(shù)據(jù)鏈?* 靜態(tài)內(nèi)部類,包含鍵值,節(jié)點next和hash值,由于他的存在,才會讓table數(shù)組項以鏈表方式存在?*/static class Entry<K,V> implements Map.Entry<K,V> {? ? ? ? final K key;? ? ? ? V value;? ? ? ? Entry<K,V> next;? ? ? ? int hash;?? ? ? ? //添加新條目? ? ? ? Entry(int h, K k, V v, Entry<K,V> n) {? ? ? ? ? ? value = v;? ? ? ? ? ? next = n;? ? ? ? ? ? key = k;? ? ? ? ? ? hash = h;? ? ? ? }?? ? ? ? public final K getKey() {? ? ? ? ? ? return key;? ? ? ? }?? ? ? ? public final V getValue() {? ? ? ? ? ? return value;? ? ? ? }?? ? ? ? public final V setValue(V newValue) {? ? ? ? ? ? V oldValue = value;? ? ? ? ? ? value = newValue;? ? ? ? ? ? return oldValue;? ? ? ? }? ? ? ? 。? ? ? ? 。? ? ? ? 。? ? ? ? 。? ? ? ? 。?/**? *? 三、存? *? 實現(xiàn)快速存取? *? 添加數(shù)據(jù)? */public V put(K key, V value) {? ? ? ? //如果數(shù)組為空,添加數(shù)組容量? ? ? ? if (table == EMPTY_TABLE) {? ? ? ? ? ? inflateTable(threshold);? ? ? ? }? ? ? ? //如果key為空,保存null在table的第一個位置,所以HashMap可以為null? ? ? ? if (key == null)? ? ? ? ? ? return putForNullKey(value);? ? ? ? //計算hash值? ? ? ? int hash = hash(key);? ? ? ? //計算key的hash值在table中的位置(索引)? ? ? ? int i = indexFor(hash, table.length);? ? ? ? //從i迭代e,找到key保存的位置? ? ? ? for (Entry<K,V> e = table[i]; e != null; e = e.next) {? ? ? ? ? ? Object k;? ? ? ? ? ? //判斷該鏈上是否有hash(key)值相同的情況,若存在,則將其value值覆蓋,保留新value? ? ? ? ? ? //新值等于舊值,返回舊值? ? ? ? ? ? if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {? ? ? ? ? ? ? ? V oldValue = e.value;? ? ? ? ? ? ? ? e.value = value;? ? ? ? ? ? ? ? e.recordAccess(this);? ? ? ? ? ? ? ? return oldValue;? ? ? ? ? ? }? ? ? ? }? ? ? ? //修改次數(shù)加一? ? ? ? modCount++;? ? ? ? //將key,value值添加在i處? ? ? ? addEntry(hash, key, value, i);? ? ? ? return null;? ? }//都是添加Entry,這個是HashMap實際容量超過容器容量,下面的方法是沒超過的情況void addEntry(int hash, K key, V value, int bucketIndex) {? ? ? ? //當(dāng)HashMap大小不小于臨界值(容量*負(fù)載因子)大小,并且數(shù)組bucketIndex位置不為null,改變HashMap大小,記錄索引? ? ? ? if ((size >= threshold) && (null != table[bucketIndex])) {? ? ? ? ? ? resize(2 * table.length);? ? ? ? ? ? hash = (null != key) ? hash(key) : 0;? ? ? ? ? ? bucketIndex = indexFor(hash, table.length);? ? ? ? }? ? ? ? //否則調(diào)用createEntry方法? ? ? ? createEntry(hash, key, value, bucketIndex);? ? }?//HashMap實際容量未超過默認(rèn)容量或者初始化容量void createEntry(int hash, K key, V value, int bucketIndex) {? ? ? ? //保存bucketIndex的所在位置到e中? ? ? ? Entry<K,V> e = table[bucketIndex];? ? ? ? //設(shè)置bucketIndex位置元素為新Entry,并且設(shè)置e為新Entry下一個節(jié)點? ? ? ? table[bucketIndex] = new Entry<>(hash, key, value, e);? ? ? ? size++;? ? }/**? * ?四、取? *? 實現(xiàn)快速存取? *? 獲取數(shù)據(jù)? */public V get(Object key) {? ? ? ? //若key為null,調(diào)用getForNullKey取出value? ? ? ? if (key == null)? ? ? ? ? ? return getForNullKey();? ? ? ? //根據(jù)key值算出hash值并取出table對應(yīng)索引處的值? ? ? ? Entry<K,V> entry = getEntry(key);?? ? ? ? return null == entry ? null : entry.getValue();? ? }?final Entry<K,V> getEntry(Object key) {? ? ? ? if (size == 0) {? ? ? ? ? ? return null;? ? ? ? }? ? ? ? //計算hash值? ? ? ? int hash = (key == null) ? 0 : hash(key);? ? ? ? //根據(jù)hash值取出table對應(yīng)索引處的值? ? ? ? for (Entry<K,V> e = table[indexFor(hash, table.length)];? ? ? ? ? ? ?e != null;? ? ? ? ? ? ?e = e.next) {? ? ? ? ? ? Object k;? ? ? ? ? ? if (e.hash == hash &&? ? ? ? ? ? ? ? ((k = e.key) == key || (key != null && key.equals(k))))? ? ? ? ? ? ? ? return e;? ? ? ? }? ? ? ? return null;}
總結(jié)
以上是生活随笔為你收集整理的【学习笔记-集合】HashMap 源码浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【问链财经-区块链基础知识系列】 第四十
- 下一篇: hash表学习笔记