Java SE HashMap的底层实现
Posted Steve Yu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java SE HashMap的底层实现相关的知识,希望对你有一定的参考价值。
1.hash散列算法
由于hashmap在存储过程中是数组加链表的存储过程,所以定义数组长度为16(建议是2的n次幂的长度),之后进行每个数组的地址都指向一个链表进行存储
hash表算法可对数组长度length取余,如果length是2的n次幂,则可对length-1取位运算&
例如,任意长度8是2的3次幂,随机的int值对8取余,和对7进行&运算得到的结果是一样的
int a=33565366; System.out.println(a%8); System.out.println(a&7);
在jdk 7之前的源码中,则对hash凑得进行了2次散列处理,为了使散列更均匀
在jdk 8往后,数组长度大于8时,链表转换为红黑树,大大提高了查找速率
2.手工实现hashMap
取数据
1.首先通过key计算hashcode来得到数组的存储,再通过next便利链表进行查找比较,直到返回true的节点对象为止
2.Java中有规定,两个内容相同的(调用equals方法值为true的)对象必须有想等的hashcode,如果两个对象内容相等,而hashcode的值不一样,则会产生悖论
扩容问题
1.jdk7之前
hashMap的位桶数组,初始大小为16,实际使用时,大小可变,如果位桶数组中元素个数达到(0.75*数组length),就重新调整数组为2倍大小,扩容是个耗时的过程,相当于重新定义数组和链表,进行复制操作
2.jdk8之后
位桶数组初始大小为16,当链表长度大于8时,将链表中各个元素拷贝到红黑树上,大大提高了查找效率
3.源代码
package com.littlepage.HashMap; /** * 用于LittlePagesHashMap的Node * @author LittlePage */ public class Node<K,V> { private int hash; private K key; private V value; private Node<K,V> next; public Node(K key, V value) { super(); this.key = key; this.value = value; } public int getHash() { return hash; } public void setHash(int hash) { this.hash = hash; } public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } public Node<K, V> getNext() { return next; } public void setNext(Node<K, V> next) { this.next = next; } @Override public String toString() { return "(" + key + "," + value + ")"; } }
package com.littlepage.HashMap; public class LittlePagesHashMap<K,V> { Object[] table=new Node[16]; //位桶数组 int size;//存放键值对个数 public LittlePagesHashMap(){ table=new Node[16]; } public void put(K key,V value){ //定义了新的节点对象 Node<K,V> newNode=new Node<>(key,value); newNode.setHash(myHash(key.hashCode(), table.length)); @SuppressWarnings("unchecked") Node<K,V> temp=(Node<K, V>) table[newNode.getHash()]; if(temp==null){ table[newNode.getHash()]=newNode; }else{ while(temp.getNext()!=null){ if(temp.getKey().equals(newNode.getKey())){ temp.setValue(newNode.getValue()); size++; return; } temp=temp.getNext(); } temp.setNext(newNode); } size++; } public int myHash(int hashcode,int length){ return hashcode&(length-1); } @Override public String toString(){ StringBuilder sb=new StringBuilder(); sb.append("["); for(int i=0;i<table.length;i++){ if(table[i]==null) continue; else{ @SuppressWarnings("unchecked") Node<K,V> temp=(Node<K, V>) table[i]; sb.append(temp); while((temp=temp.getNext())!=null){ sb.append(","+temp); } sb.append("]"); } } return sb.toString(); } }
package com.littlepage.HashMap; public class Test { public static void main(String[] args) { LittlePagesHashMap<String, String> a=new LittlePagesHashMap<>(); a.put("a", "gg"); a.put("12", "pp"); System.out.println(a); } }
以上是关于Java SE HashMap的底层实现的主要内容,如果未能解决你的问题,请参考以下文章
Java中HashMap底层实现原理(JDK1.8)源码分析
Java中HashMap底层实现原理(JDK1.8)源码分析