哈希图如何在Java中工作
最常见的面试问题是<code>HashMap如何在Java中工作</code>, “如何获取和放置方法 哈希图 内部工作”。在这里,我试图通过一个简单的示例来解释内部功能。 哈希图 是最常用的之一 爪哇中的集合而不是理论,我们将首先从示例开始,这样您将更好地理解,然后我们将了解get()和put()函数如何在 爪哇.
让’举一个非常简单的例子。我有一个 国家 类, we are going to use 国家 类 对象ect 如 键 和 它的 大写字母 (字符串)作为值。下面的示例将帮助您了解如何将这些键值对存储在哈希图中。
1. 国家.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
包 组织.Arpit.爪哇2blog; 上市 类 国家 { 串 名称; 长 人口; 上市 国家(串 名称, 长 人口) { 超(); 这个.名称 = 名称; 这个.人口 = 人口; } 上市 串 得到Name() { 返回 名称; } 上市 虚空 setName(串 名称) { 这个.名称 = 名称; } 上市 长 得到Population() { 返回 人口; } 上市 虚空 setPopulation(长 人口) { 这个.人口 = 人口; } //如果国家/地区对象的名称长度为偶数,则返回31(任何随机数),如果为奇数,则返回95(任何随机数)。 //这不是按以下方法生成哈希码的好习惯,但我这样做是为了更好,更轻松地理解哈希图。 @覆写 上市 整型 杂凑Code() { 如果(这个.名称.长度()%2==0) 返回 31; 其他 返回 95; } @覆写 上市 布尔值 等于(目的 对象) { 国家 其他 = (国家) 对象; 如果 (名称.等于IgnoreCase((其他.名称))) 返回 真正; 返回 假; } } |
如果您想了解更多关于哈希码和equals对象的方法,可以参考 爪哇中的hashcode()和equals()方法
2. 哈希图Structure.java
(主班)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
进口 爪哇.实用程序.哈希图; 进口 爪哇.实用程序.迭代器; 上市 类 哈希图Structure { / ** * @作者Arpit Mandliya */ 上市 静态的 虚空 主要(串[] args) { 国家 印度=新 国家(“印度”,1000); 国家 日本=新 国家(“日本”,10000); 国家 法国=新 国家(“法国”,2000); 国家 俄国=新 国家(“俄国”,20000); 哈希图<国家, 串> countryCapitalMap=新 哈希图<国家,串>(); countryCapitalMap.放(印度,“德里”); countryCapitalMap.放(日本,“东京”); countryCapitalMap.放(法国,“巴黎”); countryCapitalMap.放(俄国,“莫斯科”); 迭代器 countryCapitalIter=countryCapitalMap.键Set().迭代器();//将调试点放在这一行 而(countryCapitalIter.hasNext()) { 国家 countryObj=countryCapitalIter.下一页(); 串 首都=countryCapitalMap.得到(countryObj); 系统.出.打印(countryObj.得到Name()+“ ----”+首都); } } } |
-
- 有一个 条目[] 数组称为表,大小为16。
- 该表存储条目类’的对象。 哈希图类具有一个内部类,称为 条目 。该条目具有键值作为实例变量。让’请参见入口类Entry Structure的结构。
1 2 3 4 5 6 7 8 9 10 |
静态的 类 条目 实施 地图.条目 { 最后 K 键; V 值; 条目 下一页; 最后 整型 杂凑; ...//More 码 goes here } |
- 每当我们尝试将任何键值对放入哈希图中时,实例化Entry类对象的键值并将该对象存储在上述内容中 条目[] (表)。现在您一定想知道,上面创建的Entry对象将存储在哪里(表中的确切位置)。答案是,通过调用Hascode()方法为密钥计算哈希码。该哈希码用于计算上述Entry []表的索引。
- 现在,如果您在上图中的数组索引10处看到,它就有一个名为 哈希图$条目 .
- We have 放 4 键-values in 哈希图 但似乎只有2个!!!这是因为如果两个对象具有相同的哈希码,则它们将存储在相同的索引处。现在的问题是如何产生的?它以以下形式存储对象 链表 (logically).
So how 哈希码 of above country 键-value pairs are calculated.
1 2 3 4 5 6 |
哈希码 对于 日本 = 95 如 它的 长度 是 奇. 哈希码 对于 印度 =95 如 它的 长度 是 奇 哈希码 对于 俄国=31 如 它的 长度 是 甚至. 哈希码 对于 法国=31 如 它的 长度 是 甚至. |
下图将清楚地说明LinkedList概念。
所以现在如果您对 哈希图 结构,让我们通过放置和获取方法。
放
让’看一下put方法的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/ ** *将指定值与该映射中的指定键相关联。如果 * map previously contained a mapping 对于 the 键, the old 值 是 * replaced. * * @param 键 * 指定值将与之关联的键 * @param 值 * value to be 如sociated with the specified 键 * @返回与之关联的先前值<tt>key</tt>, or <tt>null</tt> * 如果没有映射<tt>key</tt>. (A <tt>null</tt> 返回 * 也可以指示先前关联的地图 * <tt>null</tt> with <tt>key</tt>.) */ 上市 V 放(K 键, V 值) { 如果 (键 == 空值) 返回 放ForNullKey(值); 整型 杂凑 = 杂凑(键.杂凑Code()); 整型 i = indexFor(杂凑, 表.长度); 对于 (条目 e = 表[i]; e != 空值; e = e.下一页) { 目的 k; 如果 (e.杂凑 == 杂凑 && ((k = e.键) == 键 || 键.等于(k))) { V 旧值 = e.值; e.值 = 值; e.recordAccess(这个); 返回 旧值; } } modCount++; addEntry(杂凑, 键, 值, i); 返回 空值; } |
- 检查键对象是否为空。如果key为null,则将其存储在 表[0] because 哈希码 对于 空值 是 always 0.
- 关键对象’s 哈希码() 方法被调用并计算哈希码。该哈希码用于查找用于存储Entry对象的数组的索引。有时可能会发生此哈希码函数编写不正确的情况,因此JDK设计人员放置了另一个函数hash(),该函数将高于计算的哈希值作为参数。如果您想了解有关hash()函数的更多信息,可以参考 杂凑map中的hash和indexFor方法.
- indexFor(杂凑,表.长度) 用于计算表数组中的确切索引以存储Entry对象。
- 正如我们在示例中所看到的,如果两个关键对象具有相同的哈希码(称为 碰撞),然后将其以链表的形式存储。因此,在这里,我们将遍历链表。
- 如果我们刚刚计算出的那个索引上没有元素,那么它将直接把Entry对象放在那个索引上。
- 如果在该索引处存在元素,则它将迭代直到获得 条目->下一页 as 空值.
- 如果我们再次输入相同的密钥,从逻辑上讲应该替换旧值该怎么办。是的,它将做到这一点。在迭代时,它将通过调用来检查密钥是否相等 等于() 方法(键.equals(k)),如果此方法返回true,则它将value对象替换为当前Entry’s 值 目的。
- If it did not find the duplicate 键, then current 条目 对象将成为链表和当前条目中的第一个节点->next将成为该索引上现有的第一个节点。
得到
让s see implementation of 得到 now:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/ ** *返回指定键所映射到的值,或者{@code 空值} * 如果 这个 map contains no mapping 对于 the 键. * * *更正式地说,如果此映射包含从键{@code k}到 *值{@code v}使得{@code(key == 空值?k == 空值: * 键.equals(k))},则此方法返回{@code v};否则返回 * {@code 空值}. (There can be at most one such mapping.) * * *返回值{@code 空值}不会<i>necessarily</i> indicate that *该映射不包含该键的映射;地图也有可能 * explicitly maps the 键 to {@code 空值}. The {@link #containsKey * containsKey}操作可用于区分这两种情况。 * * @请参阅#put(Object,Object) */ 上市 V 得到(目的 键) { 如果 (键 == 空值) 返回 得到ForNullKey(); 整型 杂凑 = 杂凑(键.杂凑Code()); 对于 (条目 e = 表[indexFor(杂凑, 表.长度)]; e != 空值; e = e.下一页) { 目的 k; 如果 (e.杂凑 == 杂凑 && ((k = e.键) == 键 || 键.等于(k))) 返回 e.值; } 返回 空值; } |
- 检查键对象是否为空。如果key为null,则Object的值位于 表[0] 将被退回。
- 关键对象’s 哈希码() method 是 called 和 杂凑 码 是 calculated.
- indexFor(hash,table.length)用于使用生成的哈希码来获取Entry对象来计算表数组中的精确索引。
- 在表数组中获取索引后,它将遍历链表并通过调用equals()方法检查键是否相等,如果返回true,则返回Entry对象的值,否则返回null。
记住要点
- 哈希图 有一个叫做 条目 which stores 键-value pairs.
- 上面的Entry对象存储在称为table的Entry [](Array)中
- 表的索引在逻辑上称为存储桶,它存储以下内容的第一个元素: 链表 .
- 关键对象’s 哈希码()用于查找那个 条目 目的。
- If two 键 对象ect ‘s have same 哈希码 ,它们将进入相同的表数组存储区。
- 关键对象‘s 等于() method 是 used to ensure uniqueness of 键 目的。
- 价值对象‘完全不使用equals()和hashcode()方法