java基础-HashMap

jdk7的HashMap实现的思路比较简单,就是一个Entry数组,数组中每个Entry都是一个链表的起点(表头)。

 1     public V put(K key, V value) {
 2         if (table == EMPTY_TABLE) {
 3             inflateTable(threshold);
 4         }
 5         //如果key为null,则将该entry放在第0位
 6         if (key == null)
 7             return putForNullKey(value);
 8         int hash = hash(key);
 9         int i = indexFor(hash, table.length);
10         //检查第i位的链表中是否存在该key,如果存在,则将原value替换为新value
11         for (Entry<K,V> e = table[i]; e != null; e = e.next) {
12             Object k;
13             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
14                 V oldValue = e.value;
15                 e.value = value;
16                 e.recordAccess(this);
17                 //并返回旧value
18                 return oldValue;
19             }
20         }
21
22         modCount++;
23         //如果不存在则将entry添加在第i位链表表头,如果(size >= threshold) && (null != table[bucketIndex])为真(threshold=capacity*loadFactor),还会涉及resize(扩容,resize(2 * table.length);)操作
24         addEntry(hash, key, value, i);
25         return null;
26     }

jdk7的hash函数

 1     final int hash(Object k) {
 2         int h = hashSeed;
 3         if (0 != h && k instanceof String) {
 4             return sun.misc.Hashing.stringHash32((String) k);
 5         }
 6
 7         h ^= k.hashCode();
 8
 9         // This function ensures that hashCodes that differ only by
10         // constant multiples at each bit position have a bounded
11         // number of collisions (approximately 8 at default load factor).
12         h ^= (h >>> 20) ^ (h >>> 12);
13         return h ^ (h >>> 7) ^ (h >>> 4);
14     }

jdk7中的HashMap存在一个问题,如果key的hash值都映射到同一个桶中,hashMap的查找就会退化成顺序查找,这会极大影响查找性能(对插入性能无影响)。jdk8为了解决这一问题,对HashMap进行了一些改进,当一个桶中的链表长度大于内设阈值(8)时,就会将该桶的链表树化(treeify),即将链表转变为一个红黑树(其余位置的链表不会受到影响)。

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

jdk8的hash函数

1     static final int hash(Object key) {
2         int h;
3         //hashCode返回一个int共32位,最终就是高16位保持原样,低16位与高16亦或后形成新的低16位。这样做是为了防止hashCode低位全0的情况,在映射后(hash&(table.length-1))就会聚集在第0位。
4         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
5     }
 1     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 2                    boolean evict) {
 3         //tab就是table,p是前驱节点,n是table长,i是key的index
 4         Node<K,V>[] tab; Node<K,V> p; int n, i;
 5         if ((tab = table) == null || (n = tab.length) == 0)
 6             n = (tab = resize()).length;
 7         //如果第i位尚没有节点,则直接插入
 8         if ((p = tab[i = (n - 1) & hash]) == null)
 9             tab[i] = newNode(hash, key, value, null);
10         else {//第i位已经存在节点的情况
11             Node<K,V> e; K k;
12             //首节点的key与即将插入的key相同
13             if (p.hash == hash &&
14                 ((k = p.key) == key || (key != null && key.equals(k))))
15                 e = p;
16             //如果首节点是TreeNode,说明该位是一棵红黑树,直接插入
17             else if (p instanceof TreeNode)
18                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
19             //遍历链表进行替换或插入
20             else {
21                 for (int binCount = 0; ; ++binCount) {
22                 //如果p.next为null,则插入到链表末端
23                 if ((e = p.next) == null) {
24                         p.next = newNode(hash, key, value, null);
25                         //如果链表长度大于TREEIFY_THRESHOLD(8,不可设置)则树化
26                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
27                             treeifyBin(tab, hash);//树化该位的链表为一棵红黑树
28                         break;
29                     }
30                     //如果找到相同的key,则直接跳出,后续会更新value
31                     if (e.hash == hash &&
32                         ((k = e.key) == key || (key != null && key.equals(k))))
33                         break;
34                     p = e;
35                 }
36             }
37             //更新value
38             if (e != null) { // existing mapping for key
39                 V oldValue = e.value;
40                 if (!onlyIfAbsent || oldValue == null)
41                     e.value = value;
42                 afterNodeAccess(e);
43                 return oldValue;
44             }
45         }
46         ++modCount;
47         if (++size > threshold)
48             resize();
49         afterNodeInsertion(evict);
50         return null;
51     }
时间: 2024-10-18 08:17:29

java基础-HashMap的相关文章

不惑JAVA之JAVA基础 - HashMap

HashMap应该是平时应用开发中或是框架设计中最为常用高效的容器.在介绍HashMap之前,先介绍两个常见的区别.后期会专门介绍CurrentHashMap. hashmap 和 hashtable 区别 HashMap和HashTable有什么区别,一个比较简单的回答是: HashMap是非线程安全的,HashTable是线程安全的. HashMap的键和值都允许有null值存在,而HashTable则不行. 因为线程安全的问题,HashMap效率比HashTable的要高. hashmap

Java基础--HashMap面试题

import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * HashMap问题 * @author 15735400536 * 使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals() * 使用ArrayList,如果元素是自定义的类,要做相等判断,就必须重写hashCode()和equals() */ publ

[Java基础]HashMap的那些事

提到HashMap,使用Java语言的人来说,是再熟悉不过了.今天就简单聊聊我们认识的HashMap; 首先我们看一下Java中的HashMap类 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { private static final long serialVersionUID = 362498820763181265L;

java 基础 ---HashMap、HashTable

HashMap.HashTable区别. 1.HashMap线程不安全,HashTable线程安全: 2.HashMap的键和值都允许null值存在,而HashTable不允许: 3.HashMap的效率高于Hashtable * Hash table based implementation of the <tt>Map</tt> interface.  This * implementation provides all of the optional map operatio

Java基础——HashMap源码分析

本篇介绍的HashMap综合了ArrayList和LinkedList这两个集合的优势,它的底层是基于哈希表实现的,如果不考虑哈希冲突的话,HashMap在增删改查操作上的时间复杂度都能够达到惊人的O(1). 对于HashMap类源码中开头注释翻译: HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同.)此类不保证映射的顺序,特别是它不保

java基础---HashMap和HashTable的异同之处

1:连个都实现了Map的接口,两者的底层数据结构相同,都是transient修饰的entry数组,transient修饰的变量不会序列化即不会持久化,序列化的过程中不会包含这个变量,这个变量的生命周期仅仅是在用户的调用过程中,不能持久化到内存磁盘中.这样便于一些敏感信息的保存 2:HashMap是不安全的,不能同步,不支持多线程并发,HashTable是安全的,有同步锁,但效率低. 3:HashMap从AbstractMap继承而来,HashTable是从Dictionary继承而来 4:Has

java基础----&gt;hashMap的简单分析(一)

HashMap是一种十分常用的数据结构对象,可以保存键值对.它在项目中用的比较多,今天我们就来学习一下关于它的知识. HashMap的简单使用 一.hashMap的put和get方法 Map<String, String> map = new HashMap<>(); map.put("username", "huhx"); map.put("password", "1234"); map.put(nu

java基础-java核心知识库

1.Spring.mvc的优势,原理,流程 2.Mybatis的原理优势 3.集合里面那些对象的原理 4.扩容原理,特别是map的底层 5.Hashmap.Hashtable和cocurrentHashMap的区别,要讲出它们各自的实现原理才行,比如Hashmap的扩容机制.cocurrentHashMap的段锁原理.多线程安全性. 6.几种造线程池的方法,区别 7.线程有哪几种状态,他们是如何转换的 8.Rpc原理,以及大致流程 9.Nio和netty的区别,为什么netty的性能高,nio,

深入Java基础(四)--哈希表(1)HashMap应用及源码详解

继续深入Java基础系列.今天是研究下哈希表,毕竟我们很多应用层的查找存储框架都是哈希作为它的根数据结构进行封装的嘛. 本系列: (1)深入Java基础(一)--基本数据类型及其包装类 (2)深入Java基础(二)--字符串家族 (3)深入Java基础(三)–集合(1)集合父类以及父接口源码及理解 (4)深入Java基础(三)–集合(2)ArrayList和其继承树源码解析以及其注意事项 文章结构:(1)哈希概述及HashMap应用:(2)HashMap源码分析:(3)再次总结关键点 一.哈希概