HashMap简单实现
来源:互联网 发布:q叔淘宝店叫什么名字 编辑:程序博客网 时间:2024/05/22 05:28
HashMap
HashMap可以看成是一个 `数组+链表/红黑树` 组合成的数据结构。
HashMap,HashTable,ConcurrentHashMap是基于hash表的实现,HashTable和HashMap在代码实现上,基本上是一样的,一个是线程安全的,一个非线程安全。ConcurrentHashMap也是线程安全的,但性能比HashTable好。
重要点
在hashMap中放入(put)元素,有以下重要步骤:
计算key的hash值,获得元素在底层数组中的下标。
通过下标位置定位到底层数组里的元素。
取到第一个元素,判断放入元素的key和当前位置的key是否==或者equals,成立则替换value值,返回旧值。
如果是树,循环树中的节点,判断放入元素的key和当前节点的key是否==或者equals,成立则替换树里的value,并返回旧值,不成立就添加到树里。
第一个元素不匹配就顺着元素的链表结构循环节点,判断放入元素的key是否==或equals节点的key,成立则替换链表里value,并返回旧值,找不到就添加到链表的最后。
判断放入HashMap中的元素要不要替换当前节点的元素,key满足以下两个条件即可替换:
1、hash值相等。
2、==或equals的结果为true。
由于hash算法依赖于对象本身的hashCode方法,所以对于HashMap里的元素来说,hashCode方法和equals方法非常重要,所以equals方法和hashCode方法一般是绑定重写的, 否则会造成hashMap运行结果不正确!
几个常量
static final float DEFAULT_LOAD_FACTOR = 0.75f; //负载因子 transient int size; //逻辑长度 transient int modCount; //修改次数, 用于fail-fast int threshold; //阈值,用于扩容,一般等于 (loadFactor * capacity) //没有空数组初始化会造成空指针异常 static final Node<?,?>[] EMPTY_TABLE = {}; //HashMap的主干数组,就是一个Node数组,初始值为空数组{},主干数组的长度一定是2的次幂。 transient Node<K,V>[] table = (Node<K,V>[]) EMPTY_TABLE; static final int TREEIFY_THRESHOLD = 8; //链表红黑树转换阈值
数组元素
数组里原对象是Node。
static class Node<K,V> implements Map.Entry<K,V>{ final int hash; //hash值 final K key; V value; Node<K,V> next; //指向下一个Node的引用,组成链表结构 Node(int hash, K key, V value, Node<K,V> next) { //...省略构造函数 } }
添加Key-Value对
public V put(K key, V value){ return putVal(hash(key), key, value, false, true);}
计算hash值
static fianl int hash(Object key){ int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); //高低位优化,降低碰撞几率}
添加到链表
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n,i; /**添加元素时table为空,触发resize()**/ if((tab = table)==null || (n = table.length) == 0) n = (tab.resize()).length; /** 添加元素时 @if tab[i]位置上没有元素,直接添加 * n为table的逻辑长度,即size * i = (n - 1) & hash 算法可以保证 i 在 n-1 和 hash 之间 * @else 遍历 通过equals和==判断链表上key和hash是否和目标相同, * 是则替换,否则添加至链表尾部 **/ //1。从底层数组取值 if((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); //数组元素转成一个单向链表 else{ Node<K,V> e; K k; //2。底层数组元素匹配成功,赋值给e if((hash == p.hash) && ((k = p.key) == key || (key != null && key.equals(k))) e = p; //3。树结构处理 else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //4。底层数组第一个没匹配上,遍历查询匹配 else { for (int binCount = 0; ; ++binCount) { //添加元素到尾部 if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) //链表元素大于阈值 treeifyBin(tab, hash); //转成红黑树 break; } //同2。 if (e.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))) break; p = e; } } //替换value if (e != null) { V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null;}
添加到树
//more code here
扩容
hashMap的扩容由resize方法实现, 这个resize方法只是简单实现, 不是源码.
private Node<K, V>[] resize() { int newCap = 0; //数组为空,初始化一个数组 if (table.length == 0 || table == null){ newCap = DEFAULT_INITIAL_CAPACITY; Node<K,V>[] newTab = (Node<K,V>[]) new Node[ newCap ]; table = newTab; return newTab; } //数组逻辑长度超过阈值,扩容并复制原数组,数组长度要保证是2的幂次数. else if (size >= (threshold = (int) (loadFactor * table.length))){ newCap = table.length * 2; Node<K,V>[] newTab = (Node<K,V>[]) new Node[ newCap ]; transfer(newTab); table = newTab; return newTab; } //超过最大长度 else if (size > MAXIMUN_CAPACITY){ newCap = HashMap2.MAXIMUN_CAPACITY; return table; } return null; } /** * 把原数组的元素传到扩容后的数组 */ void transfer(Node[] newTable) { int newCapacity = newTable.length; for (Node<K,V> e : table) { while(null != e) { Node<K,V> next = e.next; int i = e.hash & (newCapacity - 1); e.next = newTable[i]; newTable[i] = e; e = next; } } }
阅读全文
0 0
- hashmap 的简单实现
- HashMap简单实现
- HashMap的简单实现
- HashMap&&HshTable以及简单实现HashMap
- HASHMAP缓存简单java实现
- 简单实现java中的hashmap
- 二维数组简单实现HashMap
- java HashMap的简单实现
- HashMap实现简单航班查询
- HashMap实现原理简单分析
- 手动HashMap的简单实现
- 简单的hashmap的实现
- HashMap实现原理分析及简单实现一个HashMap
- HashMap实现原理分析及简单实现一个HashMap
- hashMap的实现原理-自定义简单的hashMap
- 一个简单的HashMap C语言实现
- 一个简单的HashMap C语言实现
- 使用hashmap实现简单内存cache
- springboot
- eclipse导入后报错的问题
- Unable to locate Spring NamespaceHandler for XML schema namespace tp://www.springframework.org/schem
- sort-colors
- hdu 3068 最长回文(manacher算法)
- HashMap简单实现
- Python3——列表基础
- elasticsearch学习过程中遇到的问题以及处理方式(持续更新...)
- 设计模式学习笔记(单例模式)
- springboot
- Luogu-2680 (二分答案+树上差分)
- http://blog.sina.com.cn/s/blog_59fabe030102v81s.html
- Fedora下编译安装Wireshark
- okhttp+gson转化成javabean(天气接口)