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

好看的网站 你明白吗/市场调研与分析

好看的网站 你明白吗,市场调研与分析,linu安装wordpress,苏州建行网站首页前言: HashMap是我们在编程过程中非常常见的一个数据结构 主要功能是存放键值对(K-V) 我们都知道HashMap在jdk7中是以数组链表的形式构成的(JDK8的改动还是比较大的,数组链表/红黑树构成) HashMap中数组和链表的关系如下 类似…

前言:

HashMap是我们在编程过程中非常常见的一个数据结构

主要功能是存放键值对(K-V)

我们都知道HashMap在jdk7中是以数组+链表的形式构成的(JDK8的改动还是比较大的,数组+链表/红黑树构成)

HashMap中数组和链表的关系如下

 

类似这个形状:

 

 那么HashMap源码的原理到底是怎么样的呢,我们来分析一下

一、图解流程

 二、源码分析

分析一:put方法分析

1.我们new一个HashMap对象

2.点进方法

这里有两个成员变量,通过看注释我们知道

DEFAULT_INITIAL_CAPACITY是默认初始容量-必须是2的幂。

DEFAULT_LOAD_FACTOR是构造函数中未指定时使用的负载因子。

3.我们使用put存入一个键值对

点进put方法查看

public V put(K key, V value) {if (table == EMPTY_TABLE) {//若table空 就是哈希表没有初始化//使用构造函数时设置的阈值(初始容量)初始化数组tableinflateTable(threshold);}if (key == null)return putForNullKey(value);//如果key是null,就没办法计算hash值,所以放到table的第一个位置int hash = hash(key);//根据key计算hash值的方法int i = indexFor(hash, table.length);//根据hash值 获得key应该存放的数组table中位置for (Entry<K,V> e = table[i]; e != null; e = e.next) {//遍历这个位置的元素内容Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//如果这个key已经存在了,就直接覆盖掉V oldValue = e.value;e.value = value;e.recordAccess(this);//返回被覆盖掉的valuereturn oldValue;}}modCount++;//该key不存在,放入链表中(jdk7是采用的头插的方法)        addEntry(hash, key, value, i);return null;}

 put方法流程图如下:

 4.看初始化数组方法

private void inflateTable(int toSize) {// Find a power of 2 >= toSizeint capacity = roundUpToPowerOf2(toSize);//这个方法是将toSize值转变成2的幂,如果toSize=6,则capacity=8,2的4次方threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);//重新计算阈值 threshold = 容量 * 加载因子table = new Entry[capacity];//用新计算的容量初始化数组table initHashSeedAsNeeded(capacity);}

分析二:hash计算分析

final int hash(Object k) {
//将 键key 转换成 哈希码(hash值)操作 = 使用hashCode() + 4次位运算 + 5次异或运算(9次扰动)int h = hashSeed;if (0 != h && k instanceof String) {return sun.misc.Hashing.stringHash32((String) k);}h ^= k.hashCode();// This function ensures that hashCodes that differ only by// constant multiples at each bit position have a bounded// number of collisions (approximately 8 at default load factor).h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);}

但是这个hash值并不是数组的下标还要有一个运算才能得出下标:

static int indexFor(int h, int length) {// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";return h & (length-1);//将hash值与数组长度-1作与运算就是数组的下标}

以上的种种干扰变化可以有效的减少碰撞

分析三:transfer扩容机制分析:

我们在put方法的时候发现一个给数组赋值的方法addEntry

void addEntry(int hash, K key, V value, int bucketIndex) {if ((size >= threshold) && (null != table[bucketIndex])) {//发现数组长度不够了resize(2 * table.length);//调用扩容函数,新数组的长度要求是2倍的旧数组长度hash = (null != key) ? hash(key) : 0;bucketIndex = indexFor(hash, table.length);}createEntry(hash, key, value, bucketIndex);}

扩容函数:

void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;//旧数组长度if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}Entry[] newTable = new Entry[newCapacity];//创建新的数组transfer(newTable, initHashSeedAsNeeded(newCapacity));//转移旧数组内容到新的数组table = newTable;threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);//新的阈值}

转移数组函数:

void transfer(Entry[] newTable, boolean rehash) {int newCapacity = newTable.length;for (Entry<K,V> e : table) {//遍历就数组的元素while(null != e) {//元素不为空时Entry<K,V> next = e.next;if (rehash) {e.hash = null == e.key ? 0 : hash(e.key);}int i = indexFor(e.hash, newCapacity);//重新计算元素对应的新数组下标值e.next = newTable[i];newTable[i] = e;e = next;//链表下一个节点,防止链表丢失}}}

流程图解:

 分析四:获取元素源码分析

get方法

public V get(Object key) {if (key == null)//如果key是null直接返回数组第一个元素,因为数组第一个元素就是放的key=nullreturn getForNullKey();Entry<K,V> entry = getEntry(key);//获取value方法return null == entry ? null : entry.getValue();}

进入getEntry方法查看

final Entry<K,V> getEntry(Object key) {if (size == 0) {//数组长度为0,没有元素也就是获取不到就返回nullreturn null;}int hash = (key == null) ? 0 : hash(key);//计算该key的hash值for (Entry<K,V> e = table[indexFor(hash, table.length)];//indexFor函数算出下标,根据下标获取键值对对象e != null;e = e.next) {//遍历该位置的链表直到找到对应的key,如果没有旧直接返回null就好了Object k;if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;}return null;}

有了put方法的基础,get方法不论实现还是理解都是比较好理解的

获取元素流程图解:

 

到这里我们分析完了HashMap的put和get最主要的两个方法,这篇博客先写这么多,休息一下太累了

http://www.lbrq.cn/news/1339903.html

相关文章:

  • 360如何做网站优化/seo外包
  • 网站建设与开发做什么/seo谷歌外贸推广
  • 建立销售型网站/买链接网
  • 做买衣服的网站有哪些/做企业推广
  • 卡通网站建设/建站平台哪个好
  • 网站邮箱怎么做的/杭州seo搜索引擎优化
  • 海淀最新消息今天/网站关键词百度自然排名优化
  • 初学者做网站的软件/网站恶意点击软件
  • 购买网站模板/关键词快速排名怎么做
  • 基金网站制作/seo搜索引擎优化试题及答案
  • 网站备案有效期/代写软文费用全网天下实惠
  • 电视台网站建设/今晚比赛预测比分
  • 重庆招工招聘信息查询/seo外链购买
  • 微信小程序制作视频教程/南京百度seo
  • 东莞网站优化公司/seo文章代写平台
  • 无锡网站设计公司排名/泰安seo推广
  • 杭州 seo网站建设 网络服务/百度网首页
  • 怎样建设卡盟网站/网络营销最新案例
  • 下载专门做初中数学题的网站/千锋教育的真实性
  • 福州市建设局内部网站/网络营销方式有几种
  • 俄罗斯乌克兰战争最新消息/seo外包公司如何优化
  • wordpress无法创建数据库/北京网站优化seo
  • 石家庄关键词搜索引擎优化/win7优化教程
  • 网站建设公司上海做网站公司排名/小红书推广
  • dede 中英文网站/东莞网站建设哪家公司好
  • 品牌高端网站制作企业/黑五类广告推广
  • django网站开发教程/能打开的a站
  • 网站底部的制作/黄页引流推广链接
  • 江苏省建设工程竣工验收网站/网络营销渠道名词解释
  • 想开一家相亲网站 怎么做/武汉网站提升排名
  • ChatML vs Harmony:深度解析OpenAI全新对话结构格式的变化
  • Ubuntu 安装 Elasticsearch
  • 数据挖掘2.6 Perceptron Modeling 感知器建模
  • vulnhub-Beelzebub靶场通关攻略
  • WebGIS视角下基孔肯雅热流行风险地区分类实战解析
  • 计算机网络:CIDR地址块划分子网可以使用VLSM吗?