• hashmap源码探究


    hashmap简介

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

    hashmap概念

    HashMap又叫哈希表、散列表,是一种以键值对方式存储数据的数据结构,它利用不重复无序的键实现了快速查找。

    hashmap实现图

    数组+链表+红黑树(jdk8) 每个数组存的是一个entry

    为什么hashmap能允许k,v为null,而hashtable不允许

    hashmap

    hashmap的hash方法源码

    解释:hashmap里有个hash方法,进行判断,如果key为null会令hash值为0,否则高16与低16异或,,,其他方法会调用hash方法进行操作,而hashtable会调用hashcode方法进行操作,当key为null时,还调用hashcode方法的话会产生空指针异常(下面有详细介绍)

    演示:

    hashtable

    首先hashtable的源码中没有像hashmap中的hash方法

    然后看hashtable的put方法

    解析:

    • 第一个框:清楚的表示 如果加入一个value为null则丢出空指针异常
    • 第二个框:可以思考出,如果key为null,还调用hashcode方法,肯定也抛出空指针异常

    演示

    hashmap的get方法详解

    首先get方法的作用为用key取value

    get方法源码

    从get方法看出先去调用了getnode方法返回值赋给e,可以大致猜测getnode的作用是通过key取到entry对象

    getnode方法源码

    解析:

    第一个if:

    if ((tab = table) != null && (n = tab.length) > 0 &&
                (first = tab[(n - 1) & hash]) != null) {
    

    table变量:

    resize()方法初始化:就是一个数组 也就是开头的那个数组

    再看第一个if :判断数组是否为null,数组长度是否大于0,还有一个与运算求出在数组中的也是其链表第一个的entry是否为null,有一个不成立则return null;

    简单测试:

    第二个if

    if (first.hash == hash && // always check first node
                    ((k = first.key) == key || (key != null && key.equals(k))))
                    return first;
    

    其中first

    first = tab[(n - 1) & hash]
    

    表的长度减1和key的hash取与 找出entry所在链表的第一个entry

    判断hash值,key值key的equals是否相等 若相等返回第一个

    第三个if

    if ((e = first.next) != null) {
                    if (first instanceof TreeNode)
                        return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            return e;
                    } while ((e = e.next) != null);
                }
    

    第三个if是用了do while循环遍历hash值相等的该链表

    key.equals(k):用了equels,这也是为什么对象作为key需要重写hashcode和equals的原因

    找到就返回该entry

    看完这个方法,再看get方法就容易理解了

    public V get(Object key) {
            Node<K,V> e;
            return (e = getNode(hash(key), key)) == null ? null : e.value;
        }
    

    总结:通过getNode去找,找不到就返回null,找到了就返回其valuse值

    hashmap的put方法详解

    put源码

     public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    

    参数解释

     /**
         * Implements Map.put and related methods.
         *
         * @param hash hash for key
         * @param key the key
         * @param value the value to put
         * @param onlyIfAbsent if true, don't change existing value
         		只有为真时,才不要更改现有值   
         * @param evict if false, the table is in creation mode.
         	如果为false,则该表处于创建模式。
         * @return previous value, or null if none
         */
    
    首先判断table,也就是数组是否为空,为空的话就去使用inflateTable的方法(这里不多解释)初始化hashmap。
    
       如果table不为空的话,就判断key是否为空,为空的话就将放到数组的index=0的位置,如果value不为空则返回value值。
    
       如果key不为空的话,就通过key获取hash值,通过hash值和table的长度与运算获取hashCode值。
    
       通过hashCode的遍历entry<K,V>的键值对,如果key的hash值相等 并且key.equals(e.key)也相等的话,就将新的value替换掉旧的,返回旧值。(这里借用别人的总结)
    

    https://www.cnblogs.com/houstao/p/8271362.html

    我使用的是jdk11 和jdk8的源码有差异,但原理基本不变

    如有错误,请留言告诉我

  • 相关阅读:
    20100720 14:14 转:BW十日谈之标准数据源
    BW会计年度期间转换出错
    SQL Server 2005 Logon Triggers 详细介绍
    作业输出文档维护
    windows 系统监视器 以及建议阀值
    linkedserver 的使用
    DAC 连接数据库需要做些什么
    SQL Server 2008新特性 Merge 详细见联机手册
    【20110406】提高数据库可用性需要注意的问题
    索引迁移
  • 原文地址:https://www.cnblogs.com/sm1128/p/11458671.html
Copyright © 2020-2023  润新知