HashMap实现原理·二

HashMap实现原理

前言

上一期【HashMap实现原理·一】中简单说了一下hashmap中的一些常量定义和添加元素的方法。本期介绍一下hashmap是怎么取元素的。

源码分析

hashmap结构图:
在这里插入图片描述

话不多说,上源码:

	/**
	 * 这个方法就是一个判空处理,重点是getNode方法
     * Returns the value to which the specified key is mapped,
     * or {@code null} if this map contains no mapping for the key.
     *
     * <p>More formally, if this map contains a mapping from a key
     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
     * key.equals(k))}, then this method returns {@code v}; otherwise
     * it returns {@code null}.  (There can be at most one such mapping.)
     *
     * <p>A return value of {@code null} does not <i>necessarily</i>
     * indicate that the map contains no mapping for the key; it's also
     * possible that the map explicitly maps the key to {@code null}.
     * The {@link #containsKey containsKey} operation may be used to
     * distinguish these two cases.
     *
     * @see #put(Object, Object)
     */
    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
    /**
     * hashmap的取元素方法,第一个参数是key的hash值,第二个参数是key
     * Implements Map.get and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        // 对hashmap中的数组进行判空,并且判断key的hash值对应的数组位置是否为空
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            // hashmap是由数组 + 链表(红黑树)组成,数组存放的是链表(红黑树)的首个节点,这里的first指的就是链表(数组的首个节点),若first的hash值等于key的hash值,并且equals返回true,说明first就是要找的节点,直接返回
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            // 如果first不是要找的节点,判断first是否有下一个节点,如果没有说明key不存在,直接返回空
            if ((e = first.next) != null) {
            	// 如果first有下一个节点,则判断是是否树化(TreeNode)
                if (first instanceof TreeNode)
                	//树化后调用红黑树的查找方法
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                // 链表则直接用do while循环查找
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

注:在getNode方法中,有判断是否树化,如果树化调用树的查找方法。我们知道二叉树查找的时间复杂度是O(logN),而链表查找的时间复杂度是O(N),很明显O(logN)要比O(N)快,所以这也是hashmap引入树的一个优势。

        /**
         * 这里就是树的查找方法,判断目标节点和父节点值的大小,然后循环子树,直到找到或查找完成
         * Finds the node starting at root p with the given hash and key.
         * The kc argument caches comparableClassFor(key) upon first use
         * comparing keys.
         */
        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
            TreeNode<K,V> p = this;
            do {
                int ph, dir; K pk;
                TreeNode<K,V> pl = p.left, pr = p.right, q;
                if ((ph = p.hash) > h)
                    p = pl;
                else if (ph < h)
                    p = pr;
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                else if ((q = pr.find(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
            return null;
        }

结束语

本次文章简单介绍了一下hashmap的get方法,下期继续介绍hashmap其他内容。如内容有误,欢迎各路大神指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tiny丶bingo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值