HashMap如何在Java中工作?

通过优锐课学习笔记分享,我们可以看到HashMap问题在工作面试中很常见。 这也是HashMaps在Java内部如何工作的一些深入说明,分享给大家参考学习。

HashMap在内部如何工作已成为几乎所有访谈中的一个普遍问题。 几乎每个人都知道如何使用HashMap或HashMap与Hashtable之间的区别。 但是,当问题为“ HashMap如何在内部工作?”时,许多人会失败。

这个问题的答案是,它基于哈希原理工作,但听起来并不那么简单。 哈希是一种使用算法将唯一代码分配给变量或属性的机制,从而可以轻松进行检索。 真正的哈希机制在应用于同一对象时应始终返回相同的hashCode()。

然后是一个问题:“哈希如何帮助存储和检索HashMap中的值?” 许多人会说该值将存储在存储桶中,并使用键进行检索。 如果你认为这是有效的,那么你绝对是错误的。 为了证明这一点,让我们看一下HashMap类:

1 /**
2 
3      * The table, resized as necessary. Length MUST Always be a power of two.
4 
5      */
6 
7      transient Entry[] table;

那么HashMap中Entry []的用途是什么? HashMap将对象存储为Entry实例,而不是键和值。

什么是入门班?

HashMap有一个称为Entry Class的内部类,其中包含键和值。 还有一个叫做next的东西,稍后您将了解。

 

 1 static class Entry<K,V> implements Map.Entry<K,V>
 2 
 3  {
 4 
 5      final K key;
 6 
 7      V value;
 8 
 9      Entry<K,V> next;
10 
11      final int hash;
12 
13      ........
14 
15  }

你知道HashMap将Entry实例存储在数组中,而不是作为键值对存储。 为了存储值,你将使用HashMap的put()方法。 让我们深入研究一下,看看它是如何工作的。

Put()方法如何在内部工作?

该代码将如下所示:

 1 public V put(K key, V value)
 2 
 3 {
 4 
 5     if (key == null)
 6 
 7        return putForNullKey(value);
 8 
 9     int hash = hash(key.hashCode());
10 
11     int i = indexFor(hash, table.length);
12 
13     for (Entry<K,V> e = table[i]; e != null; e = e.next)
14 
15     {
16 
17         Object k;
18 
19         if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
20 
21          {
22 
23              V oldValue = e.value;
24 
25              e.value = value;
26 
27              e.recordAccess(this);
28 
29              return oldValue;
30 
31           }
32 
33      }
34 
35      modCount++;
36 
37      addEntry(hash, key, value, i);
38 
39      return null;
40 
41  }

首先,它检查给定的密钥是否为null。如果给定键为null,则它将存储在零位置,因为null的哈希码将为零。

然后通过调用hashcode方法将哈希码应用于键.hashCode()。为了在数组范围内获得值,调用了hash(key.hashCode()),它对哈希码执行一些移位操作。

indexFor()方法用于获取存储Entry对象的确切位置。

接下来是最重要的部分-如果两个不同的对象具有相同的哈希码(例如Aa和BB将具有相同的哈希码),它将存储在同一存储桶中吗?为了解决这个问题,让我们考虑一下数据结构中的LinkedList。它将具有“下一个”属性,该属性将始终指向下一个对象,与Entry类中的下一个属性指向下一个对象的方式相同。使用这种方法,具有相同哈希码的不同对象将彼此相邻放置。

对于Collision,HashMap检查下一个属性的值。如果为null,则将Entry对象插入该位置。如果下一个属性不为null,则它将保持循环运行,直到下一个属性为null,然后将Entry对象存储在那里。

如何在HashMap中防止重复密钥?

众所周知,HashMap不允许重复键,即使当我们插入具有不同值的相同键时,也仅返回最新值。

 1 import java.util.HashMap;
 2 
 3 import java.util.Map;
 4 
 5 public class HashMapEg {
 6 
 7  public static void main(String[] args) {
 8 
 9   Map map = new HashMap();
10 
11   map.put(1, "sam");
12 
13   map.put(1, "Ian");
14 
15   map.put(1, "Scott");
16 
17   map.put(null, "asdf");
18 
19   System.out.println(map);
20 
21  }
22 
23 }

对于上面的代码,您将获得输出{null = asdf,1 = Scott},因为值sam和Ian将被替换为Scott。 那么,这是怎么发生的呢?

LinkedList中的所有Entry对象将具有相同的哈希码,但是HashMap使用equals()。 此方法检查相等性,因此如果key.equals(k)为true,它将替换Entry类中的值对象而不是键。 这样,可以防止插入重复密钥。

Get()方法如何在内部工作?

将使用put()方法中几乎相同的逻辑来检索值。

 1 public V get(Object key)
 2 
 3 {
 4 
 5     if (key == null)
 6 
 7        return getForNullKey();
 8 
 9      int hash = hash(key.hashCode());
10 
11      for (Entry<K,V> e = table[indexFor(hash, table.length)];e != null;e = e.next)
12 
13      {
14 
15          Object k;
16 
17          if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
18 
19              return e.value;
20 
21      }
22 
23          return null;
24 
25  }
26 
27 1,First, it gets the hash code of the key object, which is passed, and finds the bucket location.
28 
29 2,If the correct bucket is found, it returns the value.
30 
31 3,If no match is found, it returns null.
32 
33  

如果两个键具有相同的Hashcode会发生什么?

此处将使用相同的冲突解决机制。 key.equals(k)将一直检查到它为true,如果为true,则返回它的值。

我希望本文能阐明麻烦的HashMap内部机制。 祝大家学习愉快!如有不足之处,欢迎补充评论。

抽丝剥茧,细说架构那些事--优锐课

猜你喜欢

转载自www.cnblogs.com/youruike1/p/12061105.html
今日推荐