再探HashMap------>基于jdk1.8的详细总结

前面我已经写过关于HashMap的一些总结,但总感觉不够全面,今天再谈谈HashMap,希望在我复习巩固的同时,对你也有所帮助。
上一篇地址在这Java集合详解

HashMap的内部数据结构

JDK1.7是数组+链表
JDK1.8是数组+链表+红黑树

HashMap在jdk8中相较于jdk7在底层实现方面的不同:

在这里插入图片描述

数据结构图

在这里插入图片描述

hashMap中几个重要的字段(JDK1.8)

//默认初始容量为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;

hashMap的构造方法:

//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,否则将A转化为一个比A大且差距最小的2次幂。  
    //例如传入7返回8,传入8返回8,传入9返回16
  static final int tableSizeFor(int cap) {
   
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
 
 
    //调用上面的构造方法,自定义初始容量,负载因子为默认的0.75
 public HashMap(int initialCapacity) {
   
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
 
 
    //默认构造方法,负载因子为0.75,初始容量为DEFAULT_INITIAL_CAPACITY=16,初始容量在第一次put时才会初始化
 public HashMap() {
   
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
 
 
    //传入一个MAP集合的构造方法
 public HashMap(Map<? extends K, ? extends V> m) {
   
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

HashMap的数据插入原理

在前面的文章里,我用文字表达了数据出入的详细过程如图:
在这里插入图片描述

现在用一张图来清晰解析:
在这里插入图片描述

1、判断数组是否为空,为空进行初始化,在实例化以后,底层创建了长度是16的一维数组Entry[] table。

2、数组不为空,首先,调用key所在类的hashCode()计算key1哈希值,此哈希值经过(n - 1) &
hash计算以后,得到在Entry数组中的存放位置。

3、判断table[index] 此位置上是否存在数据,没有数据就构造一个Node节点存放在 table[index] 中

4、如果此位置上存在数据,发生了hash冲突(意味着此位置上存在一个或多个数据(以链表形式存在))
    4.1 比较key1和已存在数据的哈希值,如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。
    4.2

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值