当前位置: 首页 > wzjs >正文

重庆市公司网站备案在哪了网站建设常熟

重庆市公司网站备案在哪了,网站建设常熟,ftp 如何 更新 wordpress,网络组建实训报告引言在Java编程中,HashMap是一种常见的数据结构,用于存储键值对(key-value)。HashMap提供了高效的插入、删除和查找操作,是许多应用程序的核心组件。我们知道,HashMap是用于存储key-value键值对的集合&…

引言

        在Java编程中,HashMap是一种常见的数据结构,用于存储键值对(key-value)。HashMap提供了高效的插入、删除和查找操作,是许多应用程序的核心组件。

        我们知道,HashMap是用于存储key-value键值对的集合,而key-value键值对结构是基于Map中的Entry接口实现的,所以每一个键值对也可以称为Entry。这些键值对存放在HashMap的一个数组中,这个数组是HashMap的核心部分,数组的每个位置也被称为桶。当然,HashMap的底层结构不止是数组这么简单。

        在JDK8之前,HashMap的底层结构是数组+链表的结构,数组的每一个位置存放的是一条链表。从JDK8开始,HashMap的底层结构却变成了数组+链表+红黑树的结构,基本结构如下图所示。

       

  • 数组:也称为哈希桶(Bucket),每个元素是一个链表或红黑树的头节点;
  • 链表:当哈希冲突发生时,元素会以链表形式连接在对应桶的位置;
  • 红黑树:当链表长度超过 8 且数组长度超过 64 时,链表会转换为红黑树,提高查询效率。

         下面我们将从源码角度入手了解HashMap中get和put操作的流程。


1.get操作

get 操作用于根据键查找对应的值。get 操作的步骤如下:

  1. 计算哈希值:使用哈希函数 hash() 计算键的哈希值。
  2. 确定索引:将哈希值映射到数组的索引位置。(n - 1) & hash 定位数组位置。
  3. 查找元素:在对应的桶中查找键值对。
    1. 检查头节点:直接比较第一个节点的 key 是否匹配。
    2. 红黑树查找:若头节点是红黑树节点,调用红黑树的 getTreeNode 方法。
    3. 链表查找:遍历链表,逐个比较 key。

1.1 哈希函数计算哈希值

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

通过高 16 位与低 16 位异或,减少哈希冲突。

1.2 确定数组索引

// 1. 如果哈希表不为空且数组对应位置有元素if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {}

(n - 1) & hash 定位数组位置:取余

         本质是 取 hash 的低几位,位数由 n-1 的二进制长度决定。

        假设数组长度 n = 16(二进制 10000),则 n-1 = 15(二进制 01111)。若 hash = 23(二进制 10111)。进行与运算:

hash: 0001 0111

n - 1: 0000 1111

        -------------------

结果: 0000 0111 → 转换为十进制为 7

1.3 查找元素

 // 2. 检查第一个节点是否是目标节点if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;// 3. 如果还有后续节点if ((e = first.next) != null) {// 3.1 如果是红黑树节点,调用红黑树的查找方法if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);// 3.2 否则遍历链表查找do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}
  1. 检查头节点:直接比较第一个节点的 key 是否匹配。
  2. 红黑树查找:若头节点是红黑树节点,调用红黑树的 getTreeNode 方法。
  3. 链表查找:遍历链表,逐个比较 key。

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;// 1. 如果哈希表不为空且数组对应位置有元素if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {// 2. 检查第一个节点是否是目标节点if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;// 3. 如果还有后续节点if ((e = first.next) != null) {// 3.1 如果是红黑树节点,调用红黑树的查找方法if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);// 3.2 否则遍历链表查找do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}// 4. 未找到,返回nullreturn null;
}

2. put操作

步骤:

  1. 计算哈希值:使用哈希函数 hash(key) 计算键的哈希值。
  2. 计算索引:将哈希值映射到数组的索引位置。(n - 1) & hash 定位数组位置。
  3. 插入或更新元素:在对应的桶中插入或更新键值对。
    1. 无冲突:直接在数组对应位置插入新节点。
    2. 链表冲突:遍历链表,若找到相同 key 则覆盖值,否则插入尾部;若链表长度达到 8 且数组长度 ≥ 64,转换为红黑树。
    3. 红黑树冲突:调用红黑树的插入方法。
  4. 扩容:如果若元素数量超过阈值(容量 × 负载因子),哈希表会进行扩容。

同get方法相似,前面不再赘述,这里从第三步介绍。

putVal方法

$$  putVal 方法首先检查数组是否为空,以及对应索引位置的桶是否为空。

 // 1. 如果哈希表为空或长度为0,进行扩容if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;


$$  如果桶为空,则直接插入新节点。

if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);

$$
如果桶的第一个节点匹配,则更新该节点的值。
如果桶是红黑树,则调用红黑树的插入方法。
如果桶是链表,则遍历链表查找匹配的节点,如果不存在则插入新节点。
如果链表长度超过阈值,则将链表转换为红黑树。
如果负载因子超过阈值,哈希表会进行扩容。

// 3. 如果该位置的第一个节点的key与待插入的key相同,记录该节点if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;// 4. 如果该位置是红黑树节点,调用红黑树的插入方法else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 5. 否则为链表结构,遍历链表for (int binCount = 0; ; ++binCount) {// 5.1 如果遍历到链表尾部,插入新节点if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 如果链表长度达到树化阈值(8),转换为红黑树if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// 5.2 如果在链表中找到相同key的节点,结束遍历if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// 6. 如果找到已存在的key节点,根据onlyIfAbsent决定是否覆盖valueif (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e); // 回调方法,LinkedHashMap会用到return oldValue;}

put操作源码分析

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;// 1. 如果哈希表为空或长度为0,进行扩容if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 2. 计算数组索引位置,如果该位置为空,直接插入新节点if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;// 3. 如果该位置的第一个节点的key与待插入的key相同,记录该节点if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;// 4. 如果该位置是红黑树节点,调用红黑树的插入方法else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 5. 否则为链表结构,遍历链表for (int binCount = 0; ; ++binCount) {// 5.1 如果遍历到链表尾部,插入新节点if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 如果链表长度达到树化阈值(8),转换为红黑树if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// 5.2 如果在链表中找到相同key的节点,结束遍历if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// 6. 如果找到已存在的key节点,根据onlyIfAbsent决定是否覆盖valueif (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e); // 回调方法,LinkedHashMap会用到return oldValue;}}// 7. 记录结构修改次数++modCount;// 8. 如果元素数量超过阈值,进行扩容if (++size > threshold)resize();afterNodeInsertion(evict); // 回调方法,LinkedHashMap会用到return null;
}


文章转载自:

http://Y27JwBTU.fjfjm.cn
http://UoIuRS2V.fjfjm.cn
http://pnbJ4SQw.fjfjm.cn
http://ODWiJbVF.fjfjm.cn
http://9k2zCh2C.fjfjm.cn
http://IsbKRuOO.fjfjm.cn
http://eTjuArNr.fjfjm.cn
http://kp8VL5fO.fjfjm.cn
http://n3M2tQxb.fjfjm.cn
http://bdsIKXai.fjfjm.cn
http://G6JCcB7T.fjfjm.cn
http://W4O41EDP.fjfjm.cn
http://aZ1mRPKa.fjfjm.cn
http://pe9PSZuB.fjfjm.cn
http://Q2AgqCmG.fjfjm.cn
http://9zsYcCpB.fjfjm.cn
http://70Vp9Hin.fjfjm.cn
http://MFzG0C7O.fjfjm.cn
http://Uaf8FCe2.fjfjm.cn
http://mTKleWH4.fjfjm.cn
http://cFIkvPVK.fjfjm.cn
http://8dO8Ey48.fjfjm.cn
http://t3HbCZlX.fjfjm.cn
http://ZcBwcWjo.fjfjm.cn
http://VPCmPQ7j.fjfjm.cn
http://LkiHcyHW.fjfjm.cn
http://Z4LSSxPJ.fjfjm.cn
http://tS9jzdng.fjfjm.cn
http://nbo2LIpY.fjfjm.cn
http://lbI0bou5.fjfjm.cn
http://www.dtcms.com/wzjs/610123.html

相关文章:

  • 临沂网站建设 百度优化中国工程建设管理协会网站
  • 邯郸贴吧网站苏州app制作
  • 信用网站一体化建设产品网络推广方式
  • 社交平台运营是做什么的株洲企业seo优化
  • 网站的在线支付怎么做深圳住房和建设
  • 请人做网站郑州做网站优化最好的公司
  • linux 网站建设模板阳光城最新消息
  • 上海市建设工程交易中心网站网站建设 提供源码
  • cms网站下载网站子网页设计
  • 建立网站方法网站建设云主机云服务器
  • iis网站搭建网站备案和实际的不同
  • 杭州 网站制作wordpress首页布局
  • 做粘土网站昆明昌盛网络技术有限公司
  • 做网站要那些工具WordPress推荐主机配置
  • 工信部网站备案查询步骤网络推广精准营销推广
  • 樊城区建设局网站wordpress 数学公式
  • 网站搭建dns有用吗上海有限公司黄页
  • 学做网站论坛会员账户做一个网站需要哪些步骤
  • 付网站开发费计入什么科目ui作品集展示模板
  • 医疗医院网站建设wordpress主题 食品
  • 织梦怎么制作手机网站源码所有网站收录入口
  • python做的网站哪些保护环境做网站素材
  • 美食网站开发计划湖北城乡建设网站
  • jsp开发网站开发源码美容 网站源码
  • 网页框架模板广州seo网站多少钱
  • 兰州网站seo技术厂家长沙百度首页排名
  • 网站服务器ipv6手机优化电池充电是什么意思
  • 网站建设 网站内容 采集wordpress 主题制作 视频
  • 发朋友圈吸引顾客话术免费刷seo
  • 新闻类的手机网站怎么做灰色行业seo大神