Java基础之HashMap

152 阅读2分钟

1、存储结构

static class Node<K,V> implements Map.Entry<K,V> {
    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;
    }
    .....    
}

底层数据结构是:数组+链表;在jdk1.8之后,当链表节点长度大于8时;会将链表转化为红黑树;如果节点小于等于6时候,又会将红黑树转化为链表。

2、hash算法

对key而言,如果为null,则返回0;反之得到其hashCode,然后将hashCode进行右移,再进行异或算法(即: hashCode高16位和低16位进行异或),低16位保证足够散列,保证hash值足够均衡。(返回的结果的低16位既有高16位的数字特征又有低16位的数字特征、高16位保持不变)

    0000 0000 1000 0000 1001 1100 0101 1101

^ 0000 0000 0000 0000 0000 0000 1000 0000

    0000 0000 1000 0000 1001 1100 1101 1101

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

hashCode()函数是调用native方法

public native int hashCode();

3、取模运算

一个数字对2的n次方进行取模,定义m是2的n(n>=1)次方,那么k对m进行模运算,k%m = k&(m-1)

示例如下:

  • 10%4 = 2;
  • 10&(4-1) = 3

HashMap底层是数组,在计算将key放到哪一个index下,直接将hashkey&(length-1)进行与运算(length是2的n次方)即可。

4、关于扩容问题

  • loadFactor 是装载因子,主要目的是用来确认table 数组是否需要动态扩展,默认值是0.75,比如table 数组大小为 16,装载因子为 0.75 时,threshold 就是12,当 table 的实际大小超过 12 时,table就需要动态扩容;
  • table 数组大小是由 capacity 这个参数确定的,默认是16,也可以构造时传入,最大限制是1<<30;

参考文章