HashMap源码探究

java的HashMap作为一个键值对存储基础类非常常用,下面来看下他的基本结构(针对jdk8),

它的基本数据结构如图,当一个元素进来时,若hash值没有重复则都存储在一个数组中,若是发生重复,则在所属位置生成一个链表。

HashMap最常用的方法就是put与get了,一个添加元素,一个根据key值get元素。

put(K key, V value)

//添加元素
	public V put(K key, V value) {
//		先计算key的哈希值
		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 true 若key已存在则不作任何操作
	 * @param evict       用于子类LinkedHashMap。
	 * @return previous value, or null if none
	 */
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
		 // tab:内部数组
		Node<K, V>[] tab;
		// p:hash对应的索引位中的首节点
		Node<K, V> p;
		// n:内部数组的长度
		// i:hash对应的索引位
		int n, i;
		// 首次put时,内部数组为空,扩充数组。
		if ((tab = table) == null || (n = tab.length) == 0)
			n = (tab = resize()).length;
		 // 计算数组索引,获取该索引位置的首节点,如果为null,添加一个新的节点		
		if ((p = tab[i = (n - 1) & hash]) == null)
			tab[i] = newNode(hash, key, value, null);
		else {
			Node<K, V> e;
			K k;
			 // 如果首节点的key和要存入的key相同,那么直接覆盖value的值。
			if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
				e = p;
			 // 如果首节点是红黑树的,将键值对插添加到红黑树
			else if (p instanceof TreeNode)
				e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
			 // 此时首节点为链表,如果链表中存在该键值对,直接覆盖value。
	        // 如果不存在,则在末端插入键值对。然后判断链表是否大于等于7,尝试转换成红黑树。
	        // 注意此处使用“尝试”,因为在treeifyBin方法中还会判断当前数组容量是否到达64,
	        // 否则会放弃次此转换,优先扩充数组容量。
			else {
				// 走到这里,hash碰撞了。检查链表中是否包含key,或将键值对添加到链表末尾
				for (int binCount = 0;; ++binCount) {
					 // p.next == null,到达链表末尾,添加新节点,如果长度足够,转换成树结构。
					if ((e = p.next) == null) {
						p.next = newNode(hash, key, value, null);
						if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
							treeifyBin(tab, hash);
						break;
					}
					// 检查链表中是否已经包含key
					if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
						break;
					p = e;
				}
			}
			// 覆盖value的方法。
			if (e != null) { // existing mapping for key
				V oldValue = e.value;
				if (!onlyIfAbsent || oldValue == null)
					e.value = value;
				afterNodeAccess(e);
				return oldValue;
			}
		}
		// fail-fast机制
		++modCount;
		 // 如果元素个数大于阈值,扩充数组
		if (++size > threshold)
			resize();
		afterNodeInsertion(evict);
		return null;
	}

get

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

    /**
     * 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;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            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);
            }
        }
        return null;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值