zoukankan      html  css  js  c++  java
  • HashMap 实现原理

    简介


    HashMap 根据键的 hashCode 进行数据的存取,大多数情况下可以直接定位到它的值,从而具有很高的效率,是无序的,要想具有顺序可用LinkedHashMap; 键值均可为null;是非线程安全的,如果需要满足线程安全,可以用Collections的synchronizedMap或者使用 ConcurrentHashMap。

    JDK1.7实现

    JDK1.7中HashMap采用数组+链表的实现方式,Entry 是 HashMap 中的一个内部类,他的成员变量包括:key(键)、value(值)、next(用于实现链表结构,指向下一个链表节点)、hash(存放的是当前key的hashCode)。

    put方法

    public V put(K key, V value) {
            if (table == EMPTY_TABLE) { //是否初始化
                inflateTable(threshold);
            }
            if (key == null) //放置在0号位置
                return putForNullKey(value);
            int hash = hash(key); //计算hash值
            int i = indexFor(hash, table.length);  //计算在Entry[]中的存储位置
            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); //添加到Map中
            return null;
    }

    在添加键值对时,首先判断table是否初始化,如果没有,则进行初始化;然后判断key是否为null,如果为null,放置在Entry[]的0号位置,不为null,计算在Entry[]数组的存储位置;判断该位置上是否存在元素,如果存在,则遍历该Entry[]数组位置上的链表;判断key是否存在,如果key已经存在,则用新的value值,替换点旧的value值,并将旧的value值返回;将key-vlaue生成Entry实体,添加到HashMap中的Entry[]数组中。

    get方法

    public V get(Object key) {
         if (key == null)
             //返回table[0] 的value值
             return getForNullKey();
         Entry<K,V> entry = getEntry(key);
    
         return null == entry ? null : entry.getValue();
    }
    final Entry<K,V> getEntry(Object key) {
         if (size == 0) {
             return null;
         }
    
         int hash = (key == null) ? 0 : 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 != null && key.equals(k))))
                return e;
          }
         return null;
    }

    首先计算hash值,然后调用indexFor()方法得到该key在table中的存储位置,得到该位置的单链表,遍历链表找到key和其对应的Entry,通过entry.value返回value值。

    JDK1.8实现

    在JDK1.8中,HashMap存储的数据结构由数组+链表的方式,变为数组+链表+红黑树的存储方式,提升了性能;解决了JDK1.7版在并发条件下出现死循环的问题。

    问题


    问:如果两个key的hashCode相同,如何获取值对象? 

    答:当调用get方法时,HashMap会使用key的hashCode值,找到bucket位置,因为hashCode相同,bucket会发生碰撞,然后遍历链表,通过key的equals方法找到键值对。

  • 相关阅读:
    2.5亿!华为成立新公司!
    两年半换第 4 份工作,做个总结
    不懂什么叫编程?
    Google 为什么把几十亿行代码放在一个库?
    IntelliJ 平台 2020 年路线图
    别找了,这是 Pandas 最详细教程了
    MongoDB是什么?看完你就知道了!
    有了这个神器,轻松用 Python 写 APP !
    整理出来几个比较实用的代码对比工具
    学习进度条 第六十一-七十五天 SpringMVC学习笔记
  • 原文地址:https://www.cnblogs.com/ityard/p/11143204.html
Copyright © 2011-2022 走看看