Map,百度翻译给我的解释是映射,在Java编程中,它是存储键值对(key-value)的一种容器,也是Java程序员常用的对象。这篇博客介绍下HashMap的实现;java是面向对象编程语言,jdk为java提供了丰富的API,自然而然,在java中,数据的展示形式也是多种多样的。但是在底层语言,数据的展示就不同了,一般只有两种形式,元素值(基本类型)、数组,其他的数据类型都是这两个元素的封装,今天要说的HashMap就是如此。

  HashMap通过数组对数据进行存储的(Entry[] table)。其中,数组元素对象Entry是HashMap中的一个内部类,这个内部类记录了两个关键的东西,一个是键值对;一个next,下一个Entry。下面我介绍下将一个键值对put到HashMap中的过程;将key,value put到HashMap中,

1、拿到当前这个key的hashcode,对hashcode进行空间稀疏处理,最后得到的还是一个码,这个码在同一个字节位置的不同的整数倍上是不同的;

2、拿到上一步获得的hashcode,与当前表的长度进行与计算(h & (length-1)),获取当前key在当前数组中的坐标;

3、拿到上一步中与运算获得的坐标,在表中以阈值为单位长度,相同的位置进行查找,寻找是否存在相同的key,如果存在相同的key,那么就将key进行值替换,如果没有找到key,那么进行添加;

  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))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

在这里说一下HashMap是如何进行相同的Key的查找的。在jdk中,给对象都赋予了一个身份标识,hashcode,在java中,因为一个对象在不同的特征形态下是允许有不同的hashcode的,所以,进行了第一步处理,使得一个对象只有一个hashcode;而Hashmap存储数据是通过数组,所以找制定的键值对,实际上就是找我要的key所在的键值对的位置;为此,hashmap在存储键值对时候,存储位置是根据key的hashcode和当前hashmap内存储数组的长度来进行转换而得到的(position = hashcode & (length - 1))。举个例子,实例化一个HashMap的时候,会声明存储数组table的初始化大小为16;而我要存储一个数键值对{0:"0"},那么我存储的这个键值对的位置就 0.hashcode() & (16 -1) =0;这个键值对就是存储在Hashmap中的table数组中的第一个元素;现在我再想hashmap中put进去一个元素{5:“5”},此时5.hashcode() & (16 - 1)=5,那么,我put的key为5的这个键值对存储在hashmap中的数组table中的位置就是5;然后我在想hashmap中put进去一个元素{16:16},那么我再去数组中,发现得到位置是0,但是当前这个数组,0这个位置上已经存在数了,而且还没有找到我要存的key,那么,再往这个对象中塞键值对,就用到上面我已经介绍过的Entry对象的属性,next了。

 /**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}

  上面的添加的代码,就是如果table的当前这个位置已经有元素了,这时候,你还再往这个位置上添加新元素时,这个新元素就会放到新的元素放在数组中,把之前这个位置已经存在的元素放在当前这个新元素的next上,如果后面再有新元素新增进来,这次的元素就会到后台,作为更新元素的next,那个更新的元素存储到数组table中,这样在第一段代码找可以的时候循环时,就不用挨个遍历数组元素了,只需要遍历阈值相关的制定倍数的数据,效率就高了很多,后面的get方法,用到的额也是这里put元素时的找数的方法。

这篇博客主要就是介绍Hashmap的算法,其他的细节的实现建议去看JDK源码;

最新文章

  1. Linux学习--------二
  2. Yii2 前台用户与后台用户分离
  3. Sass浅谈
  4. 关于C#读取MySql数据时,返回DataTable中某字段数据是System.Array[]形式
  5. SDL2.0的SDL_Event事件处理
  6. NET下RabbitMQ实践[WCF发布篇]
  7. ActiveMQ中的安全机制 [转]
  8. async await 异步编程杂记
  9. jQuery1.9(辅助函数)学习之—— jQuery.param( obj ); 编辑
  10. POJ3071:Football(概率DP)
  11. putty连接远程局域网的MySql(不需要单独打开plink)
  12. java中单例设计模式
  13. 【BZOJ1801】【AHOI2009】中国象棋(动态规划)
  14. python的学习笔记01_6练习
  15. git/gerrit的简介
  16. 从零开始单排学设计模式「简单工厂设计模式」黑铁 III
  17. Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(2)
  18. &#171;面向对象程序设计(java)&#187;第三周学习总结 周强 201771010141
  19. ssm中从页面到controller和数据库出现乱码问题的解决
  20. centos7之Java开发环境构建

热门文章

  1. codeforces 454 E. Little Pony and Summer Sun Celebration(构造+思维)
  2. Spring Boot2 系列教程(四)理解Spring Boot 配置文件 application.properties
  3. Hello, OpenWrite
  4. nginx部署成功却没有办法访问
  5. Failed to read artifact descriptor for xxx:jar:版本号
  6. BASK、BFSK、BPSK调制方法的Matlab程序实现
  7. 使用ant编译web工程步骤
  8. yolo进化史之yolov3
  9. 装系统 ---------- 了解 UEFI与Legacy、硬盘分区MBR和GPT
  10. request对象的方法