在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一气之下把JDK的 src 解压出来研究,扩然开朗,遂写此文,跟大家分享感受和顺便验证我理解还有没有漏洞。 这里就拿HashMap来研究吧。
HashMap可谓JDK的一大实用工具,把各个Object映射起来,实现了“键--值”对应的快速存取。但实际里面做了些什么呢?
在这之前,先介绍一下负载因子和容量的属性。大家都知道其实一个 HashMap 的实际容量就 因子*容量,其默认值是 16×0.75=12; 这个很重要,对效率很一定影响!当存入HashMap的对象超过这个容量时,HashMap 就会重新构造存取表。这就是一个大问题,我后面慢慢介绍,反正,如果你已经知道你大概要存放多少个对象,最好设为该实际容量的能接受的数字。
两个关键的方法,put和get:
先有这样一个概念,HashMap是声明了 Map,Cloneable, Serializable 接口,和继承了 AbstractMap 类,里面的 Iterator 其实主要都是其内部类Ha****erator 和其他几个 iterator 类实现,当然还有一个很重要的继承了Map.Entry 的 Entry 内部类,由于大家都有源代码,大家有兴趣可以看看这部分,我主要想说明的是 Entry 内部类。它包含了hash,value,key 和next 这四个属性,很重要。put的源码如下
public Object put(Object key, Object value) {Object k = maskNull(key);
这个就是判断键值是否为空,并不很深奥,其实如果为空,它会返回一个static Object 作为键值,这就是为什么HashMap允许空键值的原因。
int hash = hash(k);int i = indexFor(hash, table.length);
这连续的两步就是 HashMap 最牛的地方!研究完我都汗颜了,其中 hash 就是通过 key 这个Object的 hashcode 进行 hash,然后通过 indexFor 获得在Object table的索引值。
table???不要惊讶,其实HashMap也神不到哪里去,它就是用 table 来放的。最牛的就是用 hash 能正确的返回索引。其中的hash算法,我跟JDK的作者 Doug 联系过,他建议我看看《The art of programing vol3》可恨的是,我之前就一直在找,我都找不到,他这样一提,我就更加急了,可惜口袋空空啊!!!
不知道大家有没有留意 put 其实是一个有返回的方法,它会把相同键值的 put 覆盖掉并返回旧的值!如下方法彻底说明了 HashMap 的结构,其实就是一个表加上在相应位置的Entry的链表:
for (Entry e = table; e != null; e = e.next) { if (e.hash == hash && eq(k, e.key)) { Object oldvalue = e.value; e.value = value; //把新的值赋予给对应键值。 e.recordAccess(this); //空方法,留待实现 return oldvalue; //返回相同键值的对应的旧的值。 }}modCount++; //结构性更改的次数addEntry(hash, k, value, i); //添加新元素,关键所在!return null; //没有相同的键值返回}
我们把关键的方法拿出来分析:
void addEntry(int hash, Object key, Object value, int bucketIndex) {table[bucketIndex] = new Entry(hash, key, value, table[bucketIndex]);
因为 hash 的算法有可能令不同的键值有相同的hash码并有相同的table索引,如:key=“33”和key=Object g的hash都是-8901334,那它经过indexfor之后的索引一定都为i,这样在new的时候这个Entry的next就会指向这个原本的table,再有下一个也如此,形成一个链表,和put的循环对定e.next获得旧的值。到这里,HashMap的结构,大家也十分明白了吧?
if (size++ >= threshold) //这个threshold就是能实际容纳的量resize(2 * table.length); //超出这个容量就会将Object table重构
所谓的重构也不神,就是建一个两倍大的table(我在别的论坛上看到有人说是两倍加1,把我骗了),然后再一个个indexfor进去!注意!!这就是效率!!如果你能让你的HashMap不需要重构那么多次,效率会大大提高!
说到这里也差不多了,get比put简单得多,大家,了解put,get也差不了多少了。对于collections我是认为,它是适合广泛的,当不完全适合特有的,如果大家的程序需要特殊的用途,自己写吧,其实很简单。(作者是这样跟我说的,他还建议我用LinkedHashMap,我看了源码以后发现,LinkHashMap其实就是继承HashMap的,然后override相应的方法,有兴趣的同人,自己looklook)建个 Object table,写相应的算法,就ok啦。
举个例子吧,像 Vector,list 啊什么的其实都很简单,最多就多了的同步的声明,其实如果要实现像Vector那种,插入,删除不多的,可以用一个Object table来实现,按索引存取,添加等。
分享到:
相关推荐
本教程将深入分析2022年Java中HashMap的内部机制、关键属性和操作。 HashMap的核心属性包括容量(capacity)和负载因子(load factor)。容量是指HashMap可以存储的元素的最大数量,而负载因子则是HashMap在达到多...
Java HashMap原理分析 Java HashMap是一种基于哈希表的数据结构,它的存储原理是通过将Key-Value对存储在一个数组中,每个数组元素是一个链表,链表中的每个元素是一个Entry对象,Entry对象包含了Key、Value和指向...
Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序 HashMap类Java SE程序...
在Java中,HashMap是一种广泛使用的数据结构,它基于哈希表的Map接口实现。哈希表是一种通过哈希过程将键映射到特定位置的数据结构,该位置存储了键对应的值。在详细探讨Java中HashMap的工作机制之前,首先需要理解...
java hashmap 深度剖析,和hashmap 相关面试题
Java中的HashMap是一种基于散列机制的Map接口的实现,它允许我们存储键值对。键是唯一的,而值可以重复。HashMap在处理数据时非常高效,因为其操作的时间复杂度接近于O(1)。这是通过使用散列函数将键映射到相应的...
本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,虽然...
在Java编程中,HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的存储功能,具有快速存取和高效查找的特点。HashMap基于哈希表(也称为散列表)原理,通过键对象的哈希码来定位元素,进而实现O(1)...
JavaScript中的HashMap并不是内置的数据结构,但在许多开发场景中,我们需要实现类似Java中HashMap的功能,用于存储键值对数据。在JavaScript中,我们通常使用对象(Object)来模拟HashMap的行为,因为对象的属性名...
由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking ...
Java中的HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的高效存储和访问。HashMap基于哈希表(也称为散列表)原理工作,它允许用户通过键(Key)快速查找对应的值(Value)。在HashMap中,键和值...
本文通过对HashMap的分析,总结了其优缺点,并与其他存储结构进行了比较。 在用户标签处理中,使用HashMap可以快速地统计每个用户的标签合计。HashMap的实现原理基于哈希函数,通过计算键值的哈希值,将数据映射到...
java代码-使用java解决手写hashMap的源代码 ——学习参考资料:仅用于个人学习使用!
HashMap是Java编程语言中一种非常...总的来说,HashMap是Java中高效的键值对存储结构,但需要注意其线程安全性和哈希冲突可能导致的性能影响。在实际使用中,应根据需求选择合适的数据结构和哈希函数,以确保最佳性能。
### Java中HashMap, LinkedHashMap, TreeMap,HashTable的区别 在Java编程语言中,`Map`接口是集合框架中的一个重要组成部分,用于存储键值对。本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, ...
在Java编程语言中,`HashMap`是`java.util`包中的一个核心类,它属于集合框架的一部分,主要用于存储键值对的数据结构。`HashMap`基于哈希表(散列表)实现,提供了快速的插入、删除和查找操作,平均时间复杂度为O(1...
总结来说,Java 8 HashMap键与Comparable接口的结合使用,使得我们能够在保持HashMap高效性能的同时,方便地对键进行排序,特别是在使用Java 8的新特性如Stream API时。通过实现Comparable接口,我们能够自定义对象...
HashMap源码深度剖析,面试必备
面试中,HashMap的源码分析与实现是一个常见的考察点,因为它涉及到数据结构、并发处理和性能优化等多个核心领域。本篇文章将深入探讨HashMap的内部工作原理、关键特性以及其在实际应用中的考量因素。 HashMap基于...
5. 无序性:HashMap中的键值对插入顺序与遍历顺序不一定相同,除非使用LinkedHashMap,它在保持HashMap特性的基础上提供了有序性。 在使用HashMap时,需要注意以下几点: 1. 自定义键类需重写equals()和hashCode()...