HashMap原理之存和取


早上看到云栖社区的一篇关于 HashMap实现原理 的文章 结合自己掌握的和理解的 简单再次总结下HashMap的存和取的原理


HashMap继承实现结构:

java.util.HashMap<K,V> 继承了  java.util.AbstractMap<K,V>  继承了 java.lang.Object;

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

线程安全和非线程安全定义方式:

public static void main(String[] args) {
		
		// Hashmap非线程安全
		HashMap map = new HashMap();
		
		//Hashmap 线程安全的获取方法
		Map mapSynch = Collections.synchronizedMap(new HashMap(100));
		
	}

HashMap 特性:

  • HashMap 默认是非线程安全的
  • key值可以为null (原理参照下面的HashMap 源码)
  public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
		// key为null 时候,调用putForNullKey,
		// 保存null与table[0]中
		// 这是HashMap 允许为null的原因
        if (key == null)
            return putForNullKey(value);
        //省略部分代码
    }

	 private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
		//省略部分代码
    }

  • key值是唯一的
  • 保存元素是无序的

HashMap存值是怎样保证唯一性的:

名词解释:

bucketIndex:HashMap通过调用hashCode方法,获取哈希码,通过哈希码快速找到某个存放位置,这个位置称为bucketIndex(桶);

碰撞:hashCode如果相等则有冲突,对于这种情况叫碰撞

存值流程:

  1. 调用put方法存值时,HashMap会调用hashCode 方法获取哈希码,通过哈希码快速找到某个存储位置,如果 发生碰撞,则通过调用equals来比较
  2. HashMap通过hashCode和equals最终判断出key是否存在,如果存在则使用新的value 替换旧的value
  3. 如果不存在则存放心得键值对到bucketIndex位置

碰撞处理过程:

  • 当发生碰撞时,HashMap 通过单链表解决(见源码)
// 将“key-value”添加到HashMap中
    public V put(K key, V value) {
        // 若“key为null”,则将该键值对添加到table[0]中。
        if (key == null)
            return putForNullKey(value);
        // 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            // 若“该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;
            }
        }
        // 若“该key”对应的键值对不存在,则将“key-value”添加到table中
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }


HashMap读元素:

  // 获取key对应的value
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        // 获取key的hash值
        int hash = hash(key.hashCode());
        // 在“该hash值对应的链表”上查找“键值等于key”的元素
        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.equals(k)))
                return e.value;
        }
        return null;
    }

    // 获取“key为null”的元素的值
    // HashMap将“key为null”的元素存储在table[0]位置!
    private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }


取值的时候和存的时候一样,同样根据key的hashCode 取出相应的Entry对象

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值