HashMap的简易解读

特点

  1. HashMap是存储key-value形式的集合对象
  2. HashMap初始容量为16,且容量必须是2的幂。
  3. HashMap存储的key不能重复,可以存储null为key或者value,也不能重复
  4. HashMap由数组+链表组成,jdk1.8后链表长度大于8用红黑树增加查询数据
  5. HashMap是线程不安全的,Hashtable的函数都是同步的,这意味着它是线程安全的。
  6. 虽然使用Entry组成数组是有序的,当时由于加入了链表和红黑树,所以HashMap是无序的

HashMap的四个构造方法

空参构造

  • 负载因子是指当存储容量到达实际容量的多少了开始扩容,默认为0.75,也就是说初始容量为16,达到16*0.75的容量时候就开始扩容
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // 负载因子
}

自定义初始容量的构造

  • 这个调用了下面一个构造
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

自定义初始容量和负载因子的构造

  • >>>是移位运算符,和>><<不同的是,在使用该运算符的时候高位用0填充,而其他两个用的是符号填充
  • |=是指or运算符,并赋值,和+=*=表示行业相同,|表示在二进制中运算
  • 原码:数字原本的二进制字节码,最高位的标识符号位,0标识正数,1表示负数
  • 反码:正数的反码是其本身,负数的反码是符号位不变,其他位取反
  • 补码:正数的补码是其本身,负数的补码是在反码的基础上+1
public HashMap(int initialCapacity, float loadFactor) {
    //判断初始容量不能小于0
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                            initialCapacity);
    //初始容量不能大于最大值,否则就等于最大值                                        
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    //负载因子不能小于0,并且不能为null
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                            loadFactor);
    this.loadFactor = loadFactor;
    //由于HashMap容量必须大于16且为2的n次方,所以需要对传入的容量大小进行格式化,例如传入10,这需要设置为16
    this.threshold = tableSizeFor(initialCapacity);
}

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;
}

初始数据的构造

  • 泛型标识介绍:
    • E - Element (在集合中使用,因为集合中存放的是元素)
    • T - Type(Java 类)
    • K - Key(键)
    • V - Value(值)
    • N - Number(数值类型)
    • ?- 表示不确定的java类型
  • extends K> 表示传入的类型上限为K的类型,也就是说必须为K的子类
  • super K> 表示传入的类型下限为K的类型,也就是说必须为K的父类
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}
HashMapJava中的一种数据结构,提供了键值对的储和查找功能。在HashMap的底层实现中,使用了数组和链表(或者在Java 1.8中使用了红黑树)来解决哈希冲突的问题。 哈希冲突指的是当不同的键对象计算出的哈希值相同时,它们需要被储在数组的同一个位置上。为了解决哈希冲突,HashMap中使用了两种方法,分别是开放地址法和链地址法。 开放地址法是指当发生哈希冲突时,继续寻找下一个空槽位来储键值对。这个方法需要保证数组的长度是2的幂次方,通过hash & (length-1)的位运算来减少哈希冲突的概率[2]。 链地址法是指将发生哈希冲突的键值对储在同一个位置上的链表或红黑树中。这个方法在Java 1.8中使用,当链表的长度超过一定阈值时,会将链表转换为红黑树,以提高查找效率。 在HashMap中,put方法用于插入键值对。当调用put方法时,首先会计算键对象的哈希值,并与数组的长度取余来确定储位置。如果该位置已经在键值对,则根据键对象的equals方法来判断是否是同一个键,如果是,则更新对应的值,否则将新键值对插入到链表或红黑树中。如果发生哈希冲突,就会根据选择的解决冲突的方法,继续寻找下一个空槽位或者在链表或红黑树中插入键值对。如果插入后,数组中储的键值对的数量超过了负载因子(默认为0.75),就会触发扩容操作。 扩容操作会创建一个更大的数组,并将原数组中的键值对重新计算哈希值后插入到新数组中。扩容操作会在数组大小达到阈值(数组长度乘以负载因子)时触发。 总结起来,HashMap的底层实现是通过数组和链表(或红黑树)来解决哈希冲突的问题。它使用哈希值计算和位运算来确定储位置,同时使用开放地址法和链地址法来解决哈希冲突。在插入键值对时,需要计算哈希值、确定储位置,并根据解决冲突的方法进行插入。当数组中的键值对数量超过负载因子时,会触发扩容操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [HashMap 底层源码解读(一行一行读,有基础就能看懂)](https://blog.csdn.net/rain67/article/details/124043769)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值