不含红黑树部分
import java.util.Map;import java.util.Objects;/*** @author : fuyuaaa* @date : 2021-01-29 16:29*/@SuppressWarnings("all")public class MyHashMap<K, V> {/*** 默认初始容量,必须是2的指数值*/static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/*** 最大容量, 默认是2的30次方*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** 负载因子,当size达到 容量*负载因子 时 会触发扩容*/static final float DEFAULT_LOAD_FACTOR = 0.75f;/*** 树化阈值*/static final int TREEIFY_THRESHOLD = 8;/*** 取消树化的阈值*/static final int UNTREEIFY_THRESHOLD = 6;/*** 当容量大于该值时,才进行树化*/static final int MIN_TREEIFY_CAPACITY = 64;/****/static class Node<K, V> implements Map.Entry<K, V> {// 当前key的hash值final int hash;final K key;V value;// 后继指针Node<K, V> next;Node(int hash, K key, V value, Node<K, V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey() {return key;}public final V getValue() {return value;}public final String toString() {return key + "=" + value;}public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;if (o instanceof Map.Entry) {Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))return true;}return false;}}/* ---------------- Static utilities -------------- *//*** 计算key的hash值。* (h = key.hashCode()) ^ (h >>> 16)* 计算余数 (n-1) & hash 时,由于 n 比较小,hash 只有低位参与了计算,高位的计算可以认为是无效的。* 这样导致了计算结果只与低位信息有关,高位数据没发挥作用。* 为了处理这个缺陷,让高位数据与低位数据进行异或,以此加大低位信息的随机性,变相的让高位数据参与到计算中。*/static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}/*** 根据给定的容量重新计算table的容量,结果是2的指数值,如果是7则会变成8。*/static final int tableSizeFor(int cap) {int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}/*** 存储数据的table,在初次使用时会初始化,大小为2的指数值*/transient Node<K, V>[] table;/*** hashMap中存储的数量*/transient int size;/*** 修改次数,主要用于快速失败机制*/transient int modCount;/*** 扩容阈值=容量*负载因子,size到达该值时需要扩容*/int threshold;/*** 负载因子*/final float loadFactor;/*** 构造方法** @param initialCapacity 初始容量* @param loadFactor 负载因子*/public MyHashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " + loadFactor);this.loadFactor = loadFactor;this.threshold = tableSizeFor(initialCapacity);}/*** 使用默认负载因子的构造方法** @param initialCapacity 初始容量*/public MyHashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}/*** 使用默认的初始容量和负载因子*/public MyHashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR;}public int size() {return size;}public boolean isEmpty() {return size == 0;}/*** 根据key获取value** @param key* @return*/public V get(Object key) {Node<K, V> e;// 计算key的hash, 通过getNode方法获取key所在的节点return (e = getNode(hash(key), key)) == null ? null : e.value;}final Node<K, V> getNode(int hash, Object key) {/*** 几个字段的含义* tab 存储Node的数组* first 当前key的hash 所在的的链表 的 首个节点* e 当first不是的时候, 用e来遍历* n 当前table的legth, 用于计算当前key所在的index, 通过(n - 1) & hash* k 此次方法中的key*/Node<K, V>[] tab;Node<K, V> first, e;int n;K k;// 判断table是否为空 && 判断table长度是否大于0 && 判断当前key所在的index是否为空(即该index下的链表是否为空)if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {// 判断链表的头结点是不是当前查询的节点,是的话直接返回,每次查询都会走该逻辑if (first.hash == hash &&((k = first.key) == key || (key != null && key.equals(k))))return first;// 头结点不是,所以需要遍历链表,或遍历树 查询if ((e = first.next) != null) {// TODO 树的逻辑先省略// 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;}/*** 判断hashMap中是否存在该key** @param key key* @return 是否在当前hashMap中*/public boolean containKey(Object key) {return getNode(hash(key), key) != null;}public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}/*** @param hash 当前key的hash值* @param key key* @param value value* @param onlyIfAbsent 仅在不存在时put,存在时不修改值* @param evict 这里没啥用* @return 老的值,没有则为空*/final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K, V>[] tab;Node<K, V> p;// n表示table的长度,用于计算index;// i表示当前的indexint n, i;// 如果table为空或者长度为0, 说明table没有初始化,此处开始初始化if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 如果当前key的hash所在的链表为空, 则直接新建, 然后设置if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);// 到达这个else, 说明链表不为空else {// e最终表示查询到的节点Node<K, V> e;K k;// 此时p是链表的头节点, 如果此时与当前key相等, 则表示查到了if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;// TODO 头结点是树节点的情况// else if (p instanceof TreeNode)// e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);// 往链表里插入else {// 遍历链表for (int binCount = 0; ; ++binCount) {// 遍历到末尾还是不存在, 则新建一个节点挂到链表后面, 如果到达树化阈值了, 则进行树化if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) {// TODO 树化// treeifyBin(tab, hash);}break;}// 遍历的时候找到, 则退出循环, 此时e为当前key的节点if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// e!=null 说明该key之前就存在, 则此时需要通过onlyIfAbsent决定是不是需要设置值。// 不管设不设置都会返回旧值if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}// 增加modCount, 为了快速失败处理++modCount;// 如果数量已经到达 容量*负载因子的大小,则需要扩容if (++size > threshold)resize();afterNodeInsertion(evict);return null;}void afterNodeAccess(Node<K, V> p) {}void afterNodeInsertion(boolean evict) {}void afterNodeRemoval(Node<K, V> p) {}Node<K, V> newNode(int hash, K key, V value, Node<K, V> next) {return new Node<>(hash, key, value, next);}/*** 扩容** @return 扩容后的数组*/final Node<K, V>[] resize() {// 老的table、容量、扩容阈值(到达该值需要扩容)Node<K, V>[] oldTab = this.table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = this.threshold;int newCap, newThr = 0;if (oldCap > 0) {// 扩容不了了, 最大了if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}// 扩容一倍else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold}// 初始化// 该if出现的情况: 创建map时指定了容量(所以threshold会有值), 但是table还未初始化else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;// 该if出现的情况:创建map时没传参数else { // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}// 对应上面的else if (oldThr > 0)的情况if (newThr == 0) {float ft = (float) newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ?(int) ft : Integer.MAX_VALUE);}// 设置新的扩容阈值, 创建新的数组threshold = newThr;Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];table = newTab;// 如果老的table不为空, 则需要把里面的内容移到新的tableif (oldTab != null) {// 遍历数组for (int j = 0; j < oldCap; ++j) {Node<K, V> e;// 如果当前链表不为空if ((e = oldTab[j]) != null) {oldTab[j] = null;// e.next == null 说明链表只有一个节点if (e.next == null)// 直接丢到新的table里去newTab[e.hash & (newCap - 1)] = e;// TODO 树化// else if (e instanceof TreeNode)// ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);// 此处说明是链表, 且有多个节点else { // preserve orderNode<K, V> loHead = null, loTail = null;Node<K, V> hiHead = null, hiTail = null;Node<K, V> next;/***遍历链表, 根据e.hash & oldCap判断是应该挂在哪个链表* ==0 挂在原先index位置的链表* !=0 挂在原先index+oldCap位置的链表* why ->* oldCar是2的指数值, 说明二进制只有一个1(比如8 -> 1000), (e.hash & oldCap) == 0说明hash对应oldCar为1的那一位为0(比如...xxxx0xxx)* 扩容后的容量为2oldCar, 计算index时使用 (2oldCap - 1) & hash, 与 (oldCar - 1) & hash 结果相等,* 因为2oldCap - 1 与 oldCar - 1 在二进制上的区别就是前者多了一个1, 但是e.hash的那一位为0* 比如原容量 = 8 -> 1000, 新容量 = 16 -> 10000,* (e.hash & oldCap) == 0 -> 说明e.hash的倒数第四位为0, 即 ...xxxx0xxx;* 2oldCap - 1 -> 01111 ; oldCar - 1 -> 0111, 两者就差倒数第四位的1, 但是该1不会影响index的计算, 因为e.hash的倒数第四位为0* (e.hash & oldCap) != 0 -> 说明e.hash的倒数第四位为1, 即 ...xxxx1xxx;* 2oldCap - 1 -> 01111 ; oldCar - 1 -> 0111, index的计算结果, 前者比后者大倒数第四位的1, 即oldCar*/do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;} else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);// 挂到新的table下if (loTail != null) {loTail.next = null;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;}public V remove(Object key) {Node<K, V> e;return (e = removeNode(hash(key), key, null, false, true)) == null ?null : e.value;}/*** 移除节点** @param hash hash for key* @param key the key* @param value the value to match if matchValue, else ignored* @param matchValue ture -> 只有在value相等时才移除* @param movable 树节点使用字段,此处不关注* @return 不存在该节点则返回null,否则返回该节点*/final Node<K, V> removeNode(int hash, Object key, Object value,boolean matchValue, boolean movable) {Node<K, V>[] tab;Node<K, V> p;int n, index;// 判断table是否空 & hash所在index是否空if ((tab = table) != null && (n = tab.length) > 0 &&(p = tab[index = (n - 1) & hash]) != null) {Node<K, V> node = null, e;K k;V v;// 判断链表头结点是不是if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))node = p;else if ((e = p.next) != null) {// if (p instanceof TreeNode)// node = ((TreeNode<K,V>)p).getTreeNode(hash, key);// 遍历寻找// else{do {if (e.hash == hash &&((k = e.key) == key ||(key != null && key.equals(k)))) {node = e;break;}p = e;} while ((e = e.next) != null);}}// 找到节点 && (不需要匹配value || value相等)if (node != null && (!matchValue || (v = node.value) == value ||(value != null && value.equals(v)))) {// if (node instanceof TreeNode)// ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);// elseif (node == p)tab[index] = node.next;elsep.next = node.next;++modCount;--size;afterNodeRemoval(node);return node;}}return null;}}
