java中hashmap的个人理解和分析(1.8版本)

1.hashmap说明概述:

hashMap是基于哈希表的map接口的非同步实现,相对hashtable来说,是hashtable的轻量级的实现.

允许null值的出现,通过键值对来存储,主要通过get和put来操作数据的插入和查询


2.hashmap 数据结构


在java中,数据结构中有数组和链表来实现对数据的存储,

数组: 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;

     链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N).链表的特点是:寻址困难,插入和删除容易。

而hash表就是通过这两种的结合来实现的 链表加数组的一种 "链表散列 " 的结构

当同一个hash值的节点数不小于8的时候,将不再以单链表形式存储了,会被调整成一棵红黑树。这就是JDK1.8和1.7的最大区别

3.源码理解

构造函数:

1. new HashMap<String, Object>(); 通常我们都是使用这个无参的构造器去初始化 hashmap 

 这个构造方法只是单纯的去设置下,当map下次需要扩容的时候会去扩大几倍,这里默认是 0.75 

2. 第二个构造函数, 

 public HashMap(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);
    }

这里是设置一些 扩容比例和初始大小


操作方法:

1.put

  public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
这里 1.7 是全部在put里面的,在1.8 是全部放在了putVal里面


以下是复制下别人的一些说明....虚...

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,  boolean evict) { 
    	        Node<K,V>[] tab; Node<K,V> p; int n, i; 
    	        if ((tab = table) == null || (n = tab.length) == 0) //先判断,table大小,如果table为null,或者没分配空间,就resize一次            
	 n = (tab = resize()).length; 
    	        if ((p = tab[i = (n - 1) & hash]) == null)  //如果首节点为null,就创建一个首节点。
	注意到tab[i = (n - 1) & hash],(n-1)&hash才是真正的hash值,也就是存储在table的位置(index)。 
    	            tab[i] = newNode(hash, key, value, null);//创建一个新的节点         else {//到这儿了,说明碰撞了,那么就要开始处理碰撞了 
    	            Node<K,V> e; K k;//首先先去查找与待插入键值对key相同的Node,存储在e中,k是那个节点的key 
    	            if (p.hash == hash && 
    	                ((k = p.key) == key || (key != null && key.equals(k))))//p这时候是指向table[i]的那个Node,这时候先判断下table[i]这个节点是不是和我们待插入节点有相同的hash、key值。如果是就e = p                 e = p; 
    	            else if (p instanceof TreeNode)//到这儿,说明第一个节点的hash、key值与我们带插入Node的hash、key值不吻合,那么要从这个节点之后的链表节点或者树节点中查找。由于之前提到过,1.8的HashMap存储碰撞节点时,有可能是用红黑树存储

	那么先判断首节点p的类型,如果是TreeNode类型(Node的子类),那么就说明碰撞节点已经用红黑树存储,那么使用树的插入方法,如果新插入了树节点,那么e会等于null,用于后面的判断与处理                 e = 
((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);             else {//说明碰撞节点是单链表存储的 
                for (int binCount = 0;  ++binCount) {//单链表逐个向后查找                     if ((e = p.next) == null) {//e引用下一个节点,如果是null,表示没有找到同hash、key的节点 
                        p.next = newNode(hash, key, value, null);//创建一个新的节点,放到冲突链表的最后 
                        if (binCount >= TREEIFY_THRESHOLD - 1) // 注意到如果这时候冲突节点个数达到8个,那么就会treeifyBin(tab, hash)函数,看是否需要改变冲突节点的存储结构,这个treeifyBin首先回去判断当前hash表的长度,如果不足64的话,实际上就只进行resize,扩容table,如果已经达到64,那么才会将冲突项存储结构改为红黑树。 
                            treeifyBin(tab, hash);                         break;                     } 
                    if (e.hash == hash &&                         ((k = e.key) == key || 
(key != null &&key.equals(k))))//如果找到了同hash、key的节点,那么直接退出循环 
                        break; 
                    p = e;//调整下p节点                 }             } 
            if (e != null) { //退出循环后,先看e是不是为null,为null表示添加了一个新节点,而不为null表示找到了一个与待插入同hash、同key的已存节点                 V oldValue = e.value; 
                if (!onlyIfAbsent || oldValue == null)//注意到这时候要判断是不是要修改已插入节点的value值,两个条件任意满足即修改                     e.value = value; 
                afterNodeAccess(e);//这个是空函数,可以由用户根据需要覆盖                 return oldValue;             }         } 
        ++modCount;//当插入了新节点,才会运行到这儿,由于插入了新节点,整个HashMap的结构调整次数+1 
        if (++size > threshold)//HashMap中节点数+1,如果大于threshold,那么要进行一次扩容             resize(); 
        afterNodeInsertion(evict); //这个是空函数,可以由用户根据需要覆盖         return null; 




有点乱,对照源码来看还是可以看的......未完待续...






猜你喜欢

转载自blog.csdn.net/u012930316/article/details/78741408