Java常用类:HashMap类详解

⑨【从0制作自己的ros导航小车:上位机篇】04、使用gmapping建图 前面的文章已经能够实现在odom坐标系下显示小车模型和里程计数据了,本文加上激光slam必不可少的传感器雷达,先进行测试,然后直接开始建图! 阅读详情

作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)

HashMap

本文的分享是基于jdk1.8版本

1.数据结构

HashMap底层的数据结构是数组+链表,基本的数据单位是Node<K,V>,包括key,value,next。
HashMap以key的hash值为数组下标查找或添加元素,当不同的key有相同的hash值时,出现hash碰撞,就是说本来不同的key应该是对应不同的hash,那么就可以在数组的不同下标位置处存放各自的value,然而事实并不是想象中那么美好,所以出现碰撞时,需要在同一个下标位置存放两个元素,因为Node有next属性,只需把该位置元素的next指向新的元素就可以了。

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

横向就是HashMap的数组结构,通常情况下,元素都是放在不同的下标位置处,纵向是链表结构,当发生hash碰撞时,就在该下标处生成链表结构。
在这里插入图片描述

2.成员变量

//数组,存放所有的元素
transient Node<K,V>[] table;
//默认的初始容量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//默认的负载因子 
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//获取一个Node<K,V>集合,包含HashMap中的所有元素
transient Set<Map.Entry<K,V>> entrySet;
//hashMap的大小
 transient int size;
 //判断是否需要扩容的大小,阈值
 int threshold;
 //负载因子
 final float loadFactor;

3.构造函数

//自定义初始化容量和负载因子
public HashMap(int initialCapacity, float loadFactor);
//自定义初始化容量,使用默认负载因子
public HashMap(int initialCapacity);
//使用默认初始化容量和默认的负载因子
public HashMap();
public HashMap(Map<? extends K, ? extends V> m);

4.put方法

HashMap不是在构造方法处初始化table的,而是在put元素的时候初始化table。

 public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        //判断table是否为空
        if ((tab = table) == null || (n = tab.length) == 0)
        	//为空需要初始化table
            n = (tab = resize()).length;
        //计算key所在的下标位置是否有元素
        if ((p = tab[i = (n - 1) & hash]) == null)
        	//没有元素的话,直接将传入的key,value存放到相应的位置
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            //判断传入的key与已存在的key是否相等
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                //把新的元素保存下来,将value更新
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
            	//如果已有的元素key不等于新的,则需要把新的元素放到链表的尾部
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            //HaspMap中存在相同key,替换掉旧的value值
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        //将长度+1,并且判断长度是否超过了阈值
        if (++size > threshold)
        	//扩容
            resize();
        afterNodeInsertion(evict);
        return null;
    }

总结:通过key的hash值找到数组下标处有没有元素存在,没有则直接把Node放进去,有的话判断该处元素的key与传入的key是否相等,相等则用传入的value替换旧的value,不相等则在当前下标位置处放入链表的尾部。

5.get方法

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        //判断数组下标为key的hash值处是否为null
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            //不为空则判断下标处元素的key与传入的key是否相等
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                //相等就返回
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                	//不相等时,循环链表,直到找到相同key的元素
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

总结:先根据key的hash值找数组下标,如果为null,直接返回null;不为空,则判断当前元素的key是否与传入的key相等,相等则返回,不相等则循环该处的链表,直到找到相等的key。

6.resize方法

为什么需要扩容呢?因为当HashMap的元素越来越多时,发生碰撞的几率也会变大,链表会越来越多,查询和添加的效率也会变慢。所以当元素个数超过阈值就会调用resize扩容方法。注意这里的元素个数不是size,是容量*loadFactor,如果容量为16,loadFactor为0.75,那么当size>12时就会触发扩容机制。
扩容是把容量扩大两倍,然后把原来的元素重新计算hash值放入新的HashMap中,这个过程比较耗时,所以能提前预知集合大小的,尽量初始化大小。

7.其他的常用方法

//是否存在key
public boolean containsKey(Object key) {
        return getNode(hash(key), key) != null;
    }
//是否存在value    
public boolean containsValue(Object value) {
        Node<K,V>[] tab; V v;
        if ((tab = table) != null && size > 0) {
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value ||
                        (value != null && value.equals(v)))
                        return true;
                }
            }
        }
        return false;
    }
//获取所有的value值    
public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new Values();
            values = vs;
        }
        return vs;
    }    

8.循环HashMap

使用entrySet()方法可以一次性获取所有的key和value,不用循环获取value,提升效率。

 public static void main(String[] args) {
        Map<String,String> map = new HashMap<>(8);
        map.put("1","hhh");
        map.put("2","rrr");
        map.put("3","uuu");
        for(Map.Entry<String,String> entry:map.entrySet()){
            System.out.println("key:"+entry.getKey()+",value:"+entry.getValue());
        }
    }
结果:
key:1,value:hhh
key:2,value:rrr
key:3,value:uuu

9 HashMap与HashTable的异同

1.相同点:
两个都是基于哈希表实现的,每个元素是Key-value对,内部都是采用链表来解决冲突问题,容量不足时会自动扩容
2.不同点:
HashMap是线程不安全的,HashTable是线程安全的
HashMap的key和value都支持null,而HashTable的key和value不支持null

10 HashMap和LinkedHashMap的异同

1.相同点
两个都是基于哈希表实现的,每个元素是Key-value对,内部都是采用链表来解决冲突问题,容量不足时会自动扩容
2.不同点
HashMap是无序的,LinkedHashMap是有序的

注意:
1.因为HashMap的key和value都可以是null,所以使用get方法得到null,可能是不存在key,也可能是本来value就是null,所以判断HashMap里是否有某个键,应该使用containsKey

从零到一:手把手教你用C# WinForms搭建工控上位机(含Panel控件布局与事件处理详解) 本文详细介绍了如何使用C# WinForms框架从零开始搭建工控上位机系统,重点讲解了Panel控件的布局技巧和事件处理机制。通过实战案例,帮助开发者掌握界面分区规划、动态窗体切换及数据通信等核心功能,适用于工业自动化监控系统的开发。 阅读详情

相关推荐

NI数据采集卡测电流的三种‘姿势’:直接连接、外接分流电阻还是用电流互感器?看完这篇不再纠结

本文全面解析了NI数据采集卡在电流测量中的三种主流方案:直接连接、外接分流电阻和电流互感器。通过对比精度、带宽、隔离等关键参数,结合NI-DAQmx软件生态,为工业自动化、电力监测等场景提供选型指南和实战技巧,帮助工程师优化测量系统设计。

weixin_30882895的博客 420

Java基础知识讲解-HashMap类

Java基础知识汇总-HashMap

编程小鹏的博客 1257

别再只看成交量了!用通达信这个VOL监测公式,一眼识别主力吸筹与出货信号

本文详细介绍了通达信VOL监测公式的实战应用,通过彩色量柱和换手率分层技术,帮助投资者识别主力吸筹与出货信号。该公式结合动态量能标准化和多周期均线组合,提供可视化主力行为图谱,提升交易决策的准确性。

weixin_28693447的博客 656

Java知识:HashMap类详解

HashMap类详解

dupengshixu的博客 1075

数字通信:信源编码、信道编码、调制、物理信道、解调、信道解码、信源解码

在通信系统中,信息的传输通常需要经过一系列的处理步骤,确保数据可以在信道中高效且可靠地传输。以下是信源编码、信道编码、调制、物理信道、解调、信道解码、信源解码的具体含义及其常见技术的解释。

weixin_44012667的博客 4804

FLAC3D数值三轴测试

本文介绍了使用FLAC3D进行数值三轴测试的命令流程。通过建立圆柱体模型,设置Mohr-Coulomb本构模型及材料参数,施加边界条件和荷载,并定义Fish函数监测应变和应力。命令包括模型创建、网格划分、材料属性定义、边界约束、荷载施加以及结果监测等步骤。该流程可用于模拟岩土材料在三轴条件下的力学响应,为数值分析提供参考。完整代码可从指定链接下载获取。

qq_36980284的博客 99

【Java集合框架】19 ——HashMap 类

HashMap类

weixin_44735928的博客 863

搭建问答系统

数据描述 import docx import jieba from gensim.models import Word2Vec import os import numpy as np import pickle as pk import warnings from copy import deepcopy warnings.filterwarnings("ignore") from mu...

微信号:RunsenLiu 1838

java的HashMap类

文章目录java的HashMap类HashMap的增删改查HashMap的增加(put)HashMap的查找(get)HashMap的删除(remove、clear)遍历/迭代HashMapHashMap的常用方法 java的HashMap类 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。 HashMap的存储是无序的,且不能存放重复的键。 HashMap 的 key 与 value 类型可以相同也可以不同

越努力越幸运的博客 937

Vue3 - Element Plus上传组件el-upload上传多个文件时,让on-change监听事件仅执行一次并获取最终文件列表方法(开启多选文件并手动上传,拿到文件列表统一循环调用接口上传)

vue3,elementplus,Upload上传,el-upload,文件上传组件,上传组件on-change里执行多次,取消自动上传后change重复执行问题,upload上传多个文件后导致on-change执行多次拿不到最终文件列表,Element-plus的upload组件on-change不断执行怎么办,上传多个文件多次执行调用,上传多个文件时如何只执行一次on-change方法拿到最终的文件列表,vue3elementplus上传组件开启多个上传后导致change方法执行好几次,仅调用一

🏆 前端领域优质创作者 1万+

【经验&技巧】DDR仿真中的挑战与解决方案

由于DDR的数据总线具备双向数据传输功能,需要对读写模式进行独立仿真环境的创建,并且分为连续和突发模式,再加之有单端和差分信号、有数据总线和地址总线,需要在数据传输过程中额外注意串扰的影响,并选择合适的驱动和负载以找寻设计裕量与串扰强度之间的平衡,因此,实际操作步骤和分析过程还是较为繁琐耗时的,需要设计者具有足够的耐心。

一只豌豆象的博客 1642

HashMap类使用详解

Map集合

m0_65014697的博客 2306

解决pd.read_json报错ValueError: Trailing data问题

首先,我们使用open函数打开JSON文件,然后使用json.load函数将JSON文件数据解码为Python对象。在使用Python进行数据处理中,我们经常需要将JSON格式的数据读入到DataFrame中进行处理。而使用pandas库的read_json函数,就可以方便地将JSON数据读入到DataFrame中。但是有时候在读取JSON数据时,会遇到一个非常常见的错误:ValueError: Trailing data。这个错误的解决方案并不难,只需要在read_json中添加一个参数即可。

学习使你进步。 2234

HashMap详解 Java [ 基础 ] ✅

HashMap是Java中一个强大且高效的集合类,用于快速查找和存储键值对。理解其工作原理和常用操作对于提高编程效率和解决复杂问题非常有帮助。

lenyan~的博客 2万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

java中HashMap详解

 本文转自:http://alex09.javaeye.com/blog/539545java中HashMap详解HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实现类。虽然 HashMap 和 HashSet 实现的接口规范不同,但它们底层的 Hash 存储机制完全一样,甚至 HashSet 本身就采用 HashMap 来实现的。 实际上,HashSet 和

caihaijiang的专栏 14万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java Map集合详解 :HashMap类

Map 是一种键-值对(key-value)集合,Map 集合中的每一个元素都包含一个键(key)对象和一个值(value)对象。用于保存具有映射关系的数据。Map 集合里保存着两组值,一组值用于保存 Map 里的 key,另外一组值用于保存 Map 里的 value,key 和 value 都可以是任何引用类型的数据。Map 的 key 不允许重复,value 可以重复,即同一个 Map 对象的任何两个 key 通过 equals 方法比较总是返回 false。

weixin_62458944的博客 1092

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java类HashMap常用API详解

HashMap - 测试类 package HashMap_UtilityClass; import HashMap_UtilityClass.domain.Person; import java.util.*; /** * HashMap测试类 */ public class HashMapTest { public static void main(String[] args) throws CloneNotSupportedException { // 向一个映射

WanAkiko. 3209

JAVA之HashMap详解

HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存在,即主要用来存放键值对。HashMap 的实现不是同步的,这意味着它不是线程安全的。它的 key、value 都可以为 null,此外,HashMap 中的映射不是有序的。jdk1.8 之前 HashMap 由数组 + 链表组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突(两个对象调用的 hashCode 方法计算的哈希值经哈希函数算出来的地址被别的元素占用)而存在的(“拉链法”解决冲突)。

励志成为一名优秀的全能型软件开发工程师。 2328

解析Java中1000个常用类:HashMap类,你学会了吗?

HashMap类位于java.util包中,是Map接口的一个具体实现。它基于哈希表实现,允许存储null键和null值,但不保证映射的顺序。// 构造方法和主要方法省略。

良月柒 731

Java HashMap 详解

Java HashMap 详解

T_Y_F_的博客 2260

Java 中HashMap 详解

举一个简单的例子,假设我们在目前的平台有键值对 key1-value1,计算出key1的hash为1, 计算后存在table数组中下标为1的地方,假设table被序列化了,并传输到了另外的平台,并反序列化为了原来的HashMap,key1-value1仍然存在下标1的位置,当在这个平台运行get("key1")的时候,可能计算出key1的hash为2,就有可能到下标为2的地方去找该元素,这样就出错了。创建新的Node数组,将原来数组中的元素重新映射到新的数组中。2. 数组的默认长度是16。

java1527的博客 2万+

Java中HashMap详解

HashMap的扩容

攻城狮Chova的博客 5773

【Java基础】HashMap详解

全方位详解HashMap

scj1022的博客 1827

Java常用类库与API的使用详解

简单来说,类库就是一组预先编写好的类的集合,这些类为我们提供了各种常用的功能。而API(Application Programming Interface,应用程序编程接口)则是类库提供的一种接口,它允许我们调用类库中的方法来实现特定的功能。通过上面的示例,我们可以看到Java的常用类库与API在编程中的重要作用。它们为我们提供了丰富的功能和便捷的操作方式,让我们能够更专注于业务逻辑的实现,而不是被底层细节所困扰。当然,Java的类库和API远不止这些,随着你学习的深入,你会发现更多有趣和实用的工具和方法。

Jz_Stu的博客 1287

java hashmap 类,Java常用类(HashMap)

package demo01;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;public class HashMapClass {public static void print(HashMap h) {for (Map.Entry e: h.entryS...

weixin_39966602的博客 185

Java HashMap用法详解

Java 的 HashMap 是 Java 集合框架中的一个非常重要的类,它实现了 Map 接口。HashMap基于哈希表的数据结构,允许使用键-值对存储数据。这种存储方式使得HashMap 提供了非常快速的插入、查找和删除操作,平均时间复杂度为O(1)。以下是 HashMap 的一些关键特性:键的唯一性:HashMap 中的键必须是唯一的,不允许有重复的键,但值可以重复。无序性:HashMap 不保证映射的顺序,特别是它不保证顺序会随时间保持不变。

振华OPPO的博客世界 2228
上一篇: Java常用类:LinkedList类详解
下一篇: Java常用类:HashSet类详解
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值