知识大全 Java中HashMap的工作机制

Posted

篇首语:时间铭记梦想的足迹,历史镌刻奋斗的功勋。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java中HashMap的工作机制相关的知识,希望对你有一定的参考价值。

Java中HashMap的工作机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  

  现在很多的Java程序员都会把HashMap当作一个热门话题 今天我也来说一说Hashmap

  我假设你对HashMap感兴趣 另外我认为你已经了解了HashMap的基础 这里我就不再赘述HashMap是个什么东东 如果对于你来讲HashMap还是一个新概念的话 你可以去看看官方的javadoc

  目录

   一句话回答

   什么是哈希

   关于Entry类的一点介绍

   put()方法实际上做了什么

   get()方法内部工作机制

   注意点

  一句话回答

  如果任何人让我描述一下HashMap的工作机制的话 我就简单的回答 基于Hash的规则 这句话非常简单 但是要理解这句话之前 首先我们得了解什么是哈希 不是么?

  什么是哈希

  哈希简单的说就是对变量/对象的属性应用某种算法后得到的一个唯一的串 用这个串来确定变量/对象的唯一性 一个正确的哈希函数必须遵守这个准则

  当哈希函数应用在相同的对象或者equal的对象的时候 每次执行都应该返回相同的值 换句话说 两个相等的对象应该有相同的hashcode

  注 所有Java对象都从Object类继承了一个默认的hashCode()方法 这个方法将对象在内存中的地址作为整数返回 这是一个很好的hash实现 他确保了不同的对象拥有不同的hashcode

  关于Entry类的一点介绍

  一个map的定义是 一个映射键(key)到值(value)的对象 非常简单对吧

  所以 在HashMap中一定有一定的机制来存储这些键值对 使得 HashMap有一个内部类Entry 看起来像这样

  static class Entry<K V> implements Map Entry<K V>                   final K key;             V value;             Entry<K V> next;             final int hash;              //More code goes here      

  当然 Entry类有属性用来存储键值对映射 key被final标记 除了key和value 我们还能看到两个变量next和hash 接下来我们试着理解这些变量的含义

  put()方法实际上做了什么

  再进一步看put方法的实现之前 我们有必要看一看Entry实例在数组中的存储 HashMap中是这样定义的

  /**          * The table  resized as necessary  Length MUST Always be a power of o          */        transient Entry[] table; 

  现在再来看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     *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <tt>null</tt> if there was no mapping for <tt>key</tt>     *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (A <tt>null</tt> return can also indicate that the map     *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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<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;               modCount++;     addEntry(hash  key  value  i);     return null;      

  让我们一步一步的看

  首先 检查key是否为null 如果key是null值被存在table[ ]的位置 因为null的hashcode始终为 接下来 通过key的hashCode()方法计算了这个key的hash值 这个hash值被用来计算存储Entry对象的数组中的位置 JDK的设计者假设会有一些人可能写出非常差的hashCode()方法 会出现一些非常大或者非常小的hash值 为了解决这个问题 他们引入了另外一个hash函数 接受对象的hashCode() 并转换到适合数组的容量大小

  接着是indexFor(hash table length)方法 这个方法计算了entry对象存储的准确位置

  接下来就是主要的部分 我们都知道两个不相等的对象可能拥有过相同的hashCode值 两个不同的对象是怎么存储在相同的位置[叫做bucket]呢?

  答案是LinkedList 如果你记得 Entry类有一个next变量 这个变量总是指向链中的下一个变量 这完全符合链表的特点

  所以 在发生碰撞的时候 entry对象会被以链表的形式存储起来 当一个Entry对象需要被存储的时候 hashmap检查该位置是否已近有了一个entry对象 如果没有就存在那里 如果有了就检查她的next属性 如果是空 当前的entry对象就作为已经存储的entry对象的下一个节点 依次类推

  如果我们给已经存在的key存入另一个value会怎么样的?逻辑上 旧的值将被替换掉 在检测了Entry对象的存储位置后 hashmap将会遍历那个位置的entry链表 对每一个entry调用equals方法 这个链表中的所有对象都具有相同的hashCode()而equals方法都不等 如果发现equals方法有相等的就执行替换

  在这种方式下HashMap就能保证key的唯一性

  get方法的工作机制

  现在我们已经了解了HashMap中存储键值对的机制 下一个问题是 怎样从一个HashMap中查询结果

  其实逻辑跟put是一样的 如果传入的key有匹配就将该位置的value返回 如果没有就返回null

  /**     * Returns the value to which the specified key is mapped     * or @code null if this map contains no mapping for the key     *     * <p>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 &nbsp; (There can be at most one such mapping )     *     * <p>A return value of @code null does not <i>necessarily</i>     * 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 may be used to     * distinguish these o cases     *     * @see #put(Object  Object)     */    public V get(Object key)      if (key == null)     return getForNullKey();     int hash = hash(key hashCode());     for (Entry<K V> 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;      

  上面的代码看起来跟put()方法很像 除了if (e hash == hash && ((k = e key) == key || key equals(k)))

  注意点

  存储Entry对象的数据结构是一个叫做Entry类型的table数组

  数组中一个特定的索引位置称为bucket 因为它可以容纳一个LinkedList的第一个元素的对象

  Key对象的hashCode()需要用来计算Entry对象的存储位置

  Key对象的equals()方法需要用来维持Map中对象的唯一性

  get()和put()方法跟Value对象的hashCode和equals方法无关

cha138/Article/program/Java/hx/201311/26745

相关参考

知识大全 JAVA中HashMap(哈希表)的使用(List)方法

JAVA中HashMap(哈希表)的使用(List)方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下

知识大全 java源码分析之HashMap

java源码分析之HashMap  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在Java集合类

知识大全 Java中对HashMap的深度分析

Java中对HashMap的深度分析  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在Java的

知识大全 java.util.HashMap源码要点浅析

java.util.HashMap源码要点浅析  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  散

知识大全 Java HashMap 分析之一:基本结构

JavaHashMap分析之一:基本结构  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java

知识大全 分析 Java I/O 的工作机制

分析JavaI/O的工作机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  网络I/O优化  网

知识大全 Java核心 Java中多态的实现机制

Java核心Java中多态的实现机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  多态性是面向

知识大全 在JAVA中并行和并发机制的区别?

在JAVA中并行和并发机制的区别?  以下文字资料是由(本站网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!在JAVA中并行和并

知识大全 JAVA多线程中的锁机制

JAVA多线程中的锁机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  JAVA中的每个对象都可

知识大全 Java中异常机制的深入研究

Java中异常机制的深入研究  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  由于本文旨在探讨Ja