1、HashMap数据结构
了解HashMap的数据结构首先看一下HashMap的put这个方法
从put()这个方法可以看出在我们向hashmap中添加元素的时候,实际上就是调用putVal()这个方法。我们都知道hashmap是以key-value的形式添加元素的,在看putVal这个方法
可以看出HashMap的内部结构是由数组和链表构成,而且这个链表是一个单向链表。结构就是这个样子的
在putVal这个方法中维护一个Node,再看看Node的源码
从Node的源码中可以看出HashMap中的元素都是以Node形式在数组和链表上存在。而且每个Node都是由key,value构成。在hashmap中Node是以内部类的形式存在,这个node是用于封装key和value的。在node中还有一个Node<k,v> next,这个next是用于维护下一个节点的作用。所以可以看出HashMap中的链表就是一个单向链表的属性。而且在HashMap中还维护一个存储元素的属性,这个属性就是transient Node<k,v>[] table,这个属性就刚好可以验证hashmap中的数组存在。
2、HashMap中的hash算法
hash算法的作用就是用于计算当向hashmap这个集合put一个元素进来的时候,这个元素是落在数据还是链表的具体某一个位置上。我们都知道当hashmap集合put一个元素的时候,它会组成一个Node节点的形式,这个node节点到底是落在hashmap数据结构上的哪一个位置,这个时候就需要通过hash算法进行确定。
从hashmap的数据结构可以看出,当put一个元素进来的时候,这个元素在数据结构上的落点过程一定是从左到由,从上到下。所以在一定是现在数组上进行判断,确定数组上的下标位置。然后在判断这个元素是落点在数组上还是链表上。
从DEFAULT_INITIAL_CAPACITY的值可以看出hashmap中的数组默认大小是16,所以hash在计算元素在数组上的落点位置的下表一定是在0~15之间获取一个整数。所以hash算法的作用就是为了得到数组下标位置的前戏。在这个过程主要体现在两个要求
a、根据hash算法的到一个整数
b、根据这个整数控制最终是在0~15之间
3、HashMap中的hash算法的体现:
我们都知道Object是所以的类的顶级类,而且在Object中有一个hashCode的方法,这个方法是Native修饰的。所以就满足第一个要求:得到一个整数。在将这个整数与位移16这个值进行一个取模,这就可以保证它的余数一定是在0~15之间,就满足第二个要求。
看会hashmap的源码
从这个源码可以看出在HashMap中就是通过key.hashCode()获得一个整型数。因为key是惟一的。所以就保证key.hashCode()的值是相对唯一,但不是绝对唯一,所以hashmap为了保证这个hash值是唯一的,就是hash算法中通过这个32位的hash值进行一个高16位和低16位进行一个异或运算得到一个唯一的结果(这也是hashmap中解决hash冲突的做法),这种做法的目的就是为了一定要得到0~15的数。所以在hashmap中的put方法是有一个hash(key),源码如下
在看看hash(key)的源码
这样就确定了0~15的数,在通过取模运算就可以确定put进来的元素具体是落在数组上的哪个位置了