HashMap如何在Java中工作
时间:2020-02-23 14:34:14 来源:igfitidea点击:
HashMap内部的get和put方法是如何工作的?
其中我正在尝试用一个简单的例子来解释内部功能。
HashMap是Java中最常用的集合之一。
我们将首先从示例开始,以便我们将获得更好的理解,然后我们将看到java中的功能和put()函数工作。
让我们来一个非常简单的例子。
我有一个国家级,我们将使用国家类对象作为键及其首批名称(字符串)作为值。
下面的示例将理解,这些密钥值对将存储在HashMap中。
Country.java
package org.igi.theitroad; public class Country { String name; long population; public Country(String name, long population) { super(); this.name = name; this.population = population; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getPopulation() { return population; } public void setPopulation(long population) { this.population = population; } //If length of name in country object is even then return 31(any random number) and if odd then return 95(any random number). //This is not a good practice to generate hashcode as below method but I am doing so to give better and easy understanding of hashmap. @Override public int hashCode() { if(this.name.length()%2==0) return 31; else return 95; } @Override public boolean equals(Object obj) { Country other = (Country) obj; if (name.equalsIgnoreCase((other.name))) return true; return false; } }
如果我们想了解更多关于HashCode和Equals对象方法的信息,则可以在Java中引用HashCode()和equals()方法
2. HashMapStructure.java
(主类)
import java.util.HashMap; import java.util.Iterator; public class HashMapStructure { /** * @author igi Mandliya */ public static void main(String[] args) { Country Netherlands=new Country("Netherlands",1000); Country japan=new Country("Japan",10000); Country france=new Country("France",2000); Country russia=new Country("Russia",20000); HashMap<Country, String> countryCapitalMap=new HashMap<Country,String>(); countryCapitalMap.put(Netherlands,"Delhi"); countryCapitalMap.put(japan,"Tokyo"); countryCapitalMap.put(france,"Paris"); countryCapitalMap.put(russia,"Moscow"); Iterator countryCapitalIter=countryCapitalMap.keySet().iterator();//put debug point at this line while(countryCapitalIter.hasNext()) { Country countryObj=countryCapitalIter.next(); String capital=countryCapitalMap.get(countryObj); System.out.println(countryObj.getName()+"----"+capital); } } }
现在将调试点放在第24行,并右键单击"项目 - >调试" - > Java应用程序。
程序将在第24行停止执行,然后右键单击CountryCapitalMap,然后选择Watch.You将能够看到如下结构。
现在从上图中,我们可以观察以下几点
- 有一个名为tabes的条目[]数组,其具有16尺寸。
- 此表存储了条目类对象。 hashmap类有一个名为条目的内部类。此条目具有键值作为实例变量。让我们看看输入类条目结构的结构。
static class Entry implements Map.Entry { final K key; V value; Entry next; final int hash; ...//More code goes here }
- 每当我们尝试在HashMap中置于HashMap中的任何键值对时,将实例化为键值的条目类对象,并且该对象将存储在上面提到的条目中。现在我们必须想知道,在创建的条目对象上面会存储(表中的确切位置)。答案是,通过调用hascode()方法来计算哈希码。此哈希码用于计算上面条目[]表的索引。
- 现在,如果我们在上图中看到数组索引10,它有一个名为hashmap $条目的条目对象。
- 我们在hashmap中放了4个键值,但它似乎只有2 !!!!这是因为如果两个对象具有相同的哈希码,它们将存储在相同的索引上。
现在出现了问题如何?它以LinkedList(逻辑)的形式存储对象。
所以计算上述国家钥匙值对的哈希码。
Hashcode for Japan = 95 as its length is odd. Hashcode for Netherlands =95 as its length is odd HashCode for Russia=31 as its length is even. HashCode for France=31 as its length is even.
现在,如果我们对HashMap结构的良好理解,请允许通过放置并获得方法。
put
让我们看看put方法的实现:
/** * Associates the specified value with the specified key in this map. If the * map previously contained a mapping for the key, the old value is * replaced. * * @param key * key with which the specified value is to be associated * @param value * value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or <tt>null</tt> * if there was no mapping for <tt>key</tt>. (A <tt>null</tt> return * can also indicate that the map previously associated * <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry 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; } } modCount++; addEntry(hash, key, value, i); return null; }
现在让我们一步一步地了解上面的代码
- 检查键对象是否为NULL。如果键是NULL,则它将存储在表[0]中,因为空隙为null始终为0。
- 调用key对象的HashCode()方法,并计算哈希码。
此哈希码用于查找用于存储条目对象的数组索引。有时它可能会发生这种情况,这个散码函数写得很差,所以JDK设计器已经汇出了另一个名为HASH()的函数,它将上面计算的散列值作为参数。如果要了解有关Hash()函数的更多信息,可以在HashMap中引用Hash和IndexFor方法。
- indexfor(hash,table.length)用于计算用于存储条目对象的表数组中的精确索引。
- 正如我们在我们的示例中所见,如果两个关键对象具有相同的哈希码(称为碰撞),那么它将以LinkedList.so的形式存储,我们将通过我们的LinkedList迭代。
- 如果在该索引上没有提供的元素,我们刚刚计算出该索引,那么它将直接将我们的入口对象放在该索引上。
- 如果该索引存在于该索引上的元素,则它将迭代,直到它获得rest-> next作为null。
- 如果我们再次放置相同的键,逻辑上会替换旧值。是的,它会这样做。虽然迭代它将通过调用Equals()方法检查关键平等(key.equals(k)),如果此方法返回true,则替换具有当前条目的值对象的值对象。
- 如果没有找到重复的键,则当前条目对象将成为LinkedList中的第一个节点,并且当前条目 - >下一个将成为该索引上的现有第一个节点。
get
让我们看看现在的实现:
/** * Returns the value to which the specified key is mapped, or {@code null} * if this map contains no mapping for the key. * * * More formally, if this map contains a mapping from a key {@code k} to a * value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise it returns * {@code null}. (There can be at most one such mapping.) * * * A return value of {@code null} does not necessarily indicate that * the map contains no mapping for the key; it's also possible that the map * explicitly maps the key to {@code null}. The {@link #containsKey * containsKey} operation Jan be used to distinguish these two cases. * * @see #put(Object, Object) */ public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
当我们了解哈希图的功能时才。
所以要了解获得功能非常简单。
如果传递任何键以从hashmap获取值对象。
- 检查键对象是否为NULL。如果键是NULL,则对象的值驻留在表[0]中返回。
- 调用key对象的HashCode()方法,并计算哈希码。
- indexfor(hash,table.length)用于使用生成的哈希码来计算表阵列中的精确索引来获取条目对象。
- 在表阵列中获取索引后,它将通过LinkedList迭代并通过调用Equals()方法来检查关键平等,如果返回true,则返回extring对象的值返回null。