jdk1.8 HashMap详解

本文详细讲解了JDK1.8 HashMap的基础知识和源码分析,包括HashMap的结构、重要字段、构造方法、put和get过程,以及resize()方法的工作原理。通过深入理解HashMap的实现,有助于提升对Java集合框架的理解。
摘要由CSDN通过智能技术生成

JDK1.8 HashMap详解

一、基础补充
  • hash冲突解决的方式(面试中可能会问)
  1. 开放定址法:查询产生冲突的地址的下一个地址是否被占用,知道寻找到空的地址为止;
  2. 再散列法:利用散列函数对上一步的hash值再进行散列;
  3. 连地址法:对于hash值相等的,通过链表链接起来,HashMap中采用了该方式
二、源码分析
HashMap的结构

首先,hashMap的主干是一个Node数组(jdk1.7及之前为Entry数组)每一个Node包含一个key与value的键值对,与一个next,next指向下一个node,hashMap由多个Node对象组成。

Node是HhaspMap中的一个静态内部类 :

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;
        }
 
        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }
 
        public final int hashCode() {
            // 这里的hashCode使用key和value的hashcode值的异或实现
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }
 
        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
 
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }
  • 补充解释说明:
  1. Node是一个内部类,继承了Map.Entry
  2. Node的hashCode方法使用key和value的hashcode值异或运算产生
HashMap的几个重要字段
//默认初始容量为16,0000 0001 右移4位 0001 0000为16,主干数组的初始容量为16,而且这个数组
//必须是2的倍数(后面说为什么是2的倍数)
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 
//最大容量为int的最大值除2
static final int MAXIMUM_CAPACITY = 1 << 30;
 
//默认加载因子为0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
 
//阈值,如果主干数组上的链表的长度大于8,链表转化为红黑树
 static final int TREEIFY_THRESHOLD = 8;
 
//hash表扩容后,如果发现某一个红黑树的长度小于6,则会重新退化为链表
 static final int UNTREEIFY_THRESHOLD = 6;
 
//当hashmap容量大于64时,链表才能转成红黑树
 static final int MIN_TREEIFY_CAPACITY = 64;
 
//临界值=主干数组容量*负载因子
int threshold;
  • 补充解释
  1. 链表树化的临界值是8, 退化为链表的临界值是6,是为了防止链表长度若在7和8来回变化,会引起红黑树的频繁建立和退化,效率更低
构造方法
//initialCapacity为初始容量,loadFactor为负载因子
public HashMap(int initialCapacity, float loadFactor) {
        //初始容量小于0,抛出非法数据异常
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        //初始容量最大为MAXIMUM_CAPACITY
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        //负载因子必须大于0,并且是合法数字
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        
        this.loadFactor = loadFactor;
        //将初始容量转成2次幂
        this.threshold = tableSizeFor(initialCapacity);
    }
 
    //tableSizeFor的作用就是,如果传入A,当A大于0,小于定义的最大容量时,
    //  如果A是2次幂则返回A,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值