
首先将k、v封装到Node对象当中(节点)
调用k的理总hasnCode()方法取出hash值;通过hashcode值和数组长度取模得到元素存储的下标
此时分为两种情况
下标位置上没有元素,网站模板直接把元素方进入 该所以已有元素,作为知道判断该位置的层存储原元素和当前元素是否相等,使用equals来比较(默认是理总比较两个对象的地址)。如果两只相等则直接覆盖,如果不等则(Hash碰撞)在原元素下面使用链表的结构存储该元素(如果已存在链表,则插在链表尾部),每个元素节点都有一个next属性指向下一个节点,这就由数组结构变成了数组+链表;因为链表中元素太多的时候回影响查找效率,所以当链表的元素个数达到 8 的时候使用链表存储就转变成了使用红黑树存储(当红黑树上的节点数量小于 6 个,会重新把红黑树变成单向链表数据结构),原因就是红黑树是平衡二叉树,在查找性能方面比聊表要高在 JDK1.7中是在元素插入 前 进行的扩容,在JDK1.8 中是先加入元素 后 再判断是否进行扩容
在 JDK1.7 中不一定,只有存储元素超过阈值并且当前存储位置不为null,才会进行扩容,在 JDK1.8 中会进行扩容
调用对象key的hashCode方法,再对这个hashcode方法进行一些右移以及异或运算(使的hashCode的高位和低位都参与到运算中);通过右移和异或运算可以使hashMap的散列化更强,提高hashMap的get方法的效率
HashCode的存在主要是为了查找的快捷性, HashCode是用来在散列存储结构中确定对象的存储地址的 ( 用hashcode来代表对象在hash表中的位置 ) , hashCode存在的重要的原因之一就是在HashMap(HashSet其实就是HashMap)中使用(其实Object类的hashCode方法注释已经说明了),HashMap之所以速度 快 ,因为他使用的是 散列表 ,根据key的hashcode值生成数组下标(通过内存地址直接查找,不需要判断,但是需要多出很多内存,相当于以空间换时间)
归纳总结:
若重写了equals(Object obj)方法,则有必要重写hashCode()方法 若两个对象equals(Object obj)返回true,则hashCode()有必要也返回相同的int数 若两个对象equals(Object obj)返回false,则hashCode()不一定返回不同的int数 若两个对象hashCode()返回相同int数,则equals(Object obj)不一定返回true 若两个对象hashCode()返回不同int数,则equals(Object obj)一定返回false 同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题key为null的时候,只会放在hashMap的0位置(即key的hashCode为0,对数组长度取余后的下标也是0),不会有链表 在HashMap源码中对put方法对null做了处理,key为null的判断后进入putForNullKey(V value)这个方法,李里面for循环是在talbe[0]链表 中查找key为null的元素,如果找到,则将value重新赋值给这个元素的value,并返回原来的value。如果没找到则将这个元素添加到talbe[0]链表的表头
/** * HashMap的put方法 */ public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } // key为null调用putForNullKey(value) if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; } /** * Offloaded version of put for null keys */ private V putForNullKey(V value) { // for循环处理key为空的情况 for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null; }【编辑推荐】
手把手教你使用Python轻松打造淘宝主图视频生成神器 为什么 NanoID 会取代 UUID 加密货币世界中的黑客预防与缓解 最近腾讯35岁员工薪资曝光,你这辈子还能追得上吗?(责任编辑:应用开发)