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

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

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

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

 /**

      * The table, resized as necessary. Length MUST Always be a power of two.

      */

      transient Entry[] table;

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

什么是入门班?

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

 static class Entry<K,V> implements Map.Entry<K,V>

  {

      final K key;

      V value;

      Entry<K,V> next;

      final int hash;

      ........

  }

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

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

该代码将如下所示:

 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;

  }

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

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

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

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

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

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

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

 import java.util.HashMap;

 import java.util.Map;

 public class HashMapEg {

  public static void main(String[] args) {

   Map map = new HashMap();

   map.put(1, "sam");

   map.put(1, "Ian");

   map.put(1, "Scott");

   map.put(null, "asdf");

   System.out.println(map);

  }

 }

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

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

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

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

 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;

  }

 1,First, it gets the hash code of the key object, which is passed, and finds the bucket location.

 2,If the correct bucket is found, it returns the value.

 3,If no match is found, it returns null.

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

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

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

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

HashMap如何在Java中工作?的更多相关文章

  1. 如何在JAVA中实现一个固定最大size的hashMap

    如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...

  2. 如何在java中使用sikuli进行自动化测试

    很早之前写过一篇介绍sikuli的文章.本文简单介绍如何在java中使用sikuli进自动化测试. 图形脚本语言sikuli sikuli IDE可以完成常见的单击.右击.移动到.拖动等鼠标操作,ja ...

  3. 如何在Java中调用Python代码

    有时候,我们会碰到这样的问题:与A同学合作写代码,A同学只会写Python,而不会Java, 而你只会写Java并不擅长Python,并且发现难以用Java来重写对方的代码,这时,就不得不想方设法“调 ...

  4. 如何在java中跳出当前多重嵌套循环?有几种方法?

    如何在java中跳出当前多重嵌套循环?有几种方法? - 两种方法   - 1.在外层循环定义标记          ok:          for(int i=0;i<100;i++){    ...

  5. 用代码说话:如何在Java中实现线程

    并发编程是Java语言的重要特性之一,"如何在Java中实现线程"是学习并发编程的入门知识,也是Java工程师面试必备的基础知识.本文从线程说起,然后用代码说明如何在Java中实现 ...

  6. 如何在Java中测试类是否是线程安全的

    通过优锐课的java核心笔记中,我们可以看到关于如何在java中测试类是否线程安全的一些知识点汇总,分享给大家学习参考. 线程安全性测试与典型的单线程测试不同.为了测试一个方法是否是线程安全的,我们需 ...

  7. 如何在 Java 中实现无向环和有向环的检测

    无向环 一个含有环的无向图如下所示,其中有两个环,分别是 0-2-1-0 和 2-3-4-2: 要检测无向图中的环,可以使用深度优先搜索.假设从顶点 0 出发,再走到相邻的顶点 2,接着走到顶点 2 ...

  8. 如何在 Java 中实现最小生成树算法

    定义 在一幅无向图 \(G=(V,E)\) 中,\((u, v)\) 为连接顶点 \(u\) 和顶点 \(v\) 的边,\(w(u,v)\) 为边的权重,若存在边的子集 \(T\subseteq E\ ...

  9. 如何在 Java 中实现 Dijkstra 最短路算法

    定义 最短路问题的定义为:设 \(G=(V,E)\) 为连通图,图中各边 \((v_i,v_j)\) 有权 \(l_{ij}\) (\(l_{ij}=\infty\) 表示 \(v_i,v_j\) 间 ...

随机推荐

  1. 02 | Java内存模型:看Java如何解决可见性和有序性问题

    什么是 Java 内存模型? 导致可见性的原因是缓存,导致有序性的原因是编译优化,那解决可见性. 有序性最直接的办法就是禁用缓存和编译优化,但是这样问题虽然解决了,我们程序的性能可就堪忧了.   合理 ...

  2. kubernetes-概念

    kubernetes内部组件工作原理 http://dockone.io/article/5108   一.Master   Master是整个集群的控制中心,kubernetes的所有控制指令都是发 ...

  3. 利用用阿里云API实现DDNS

    前言 之前动态域名解析是用的是腾达路由器上集成的第三方动态解析服务花生壳,解析费用一年40元.后来觉得域名前缀不好,想换掉,花生壳需要重新购买新的域名解析费用,增加1条或者2条动态解析无所谓,万一以后 ...

  4. 《Java基础知识》Java instanceof 运算符

    java多态性带来一个问题,就是如何判断一个变量所实际引用对象的类型.这里java帮我们引入了 instanceof 运算符. instanceof运算符用来判断一个变量的所引用对象的实际类型,注意是 ...

  5. POJ2182题解——线段树

    POJ2182题解——线段树 2019-12-20 by juruoOIer 1.线段树简介(来源:百度百科) 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线 ...

  6. NET Framework项目移植到NET Core上遇到的一系列坑(2)

    目录 获取请求的参数 获取完整的请求路径 获取域名 编码 文件上传的保存方法 获取物理路径 返回Json属性大小写问题 webconfig的配置移植到appsettings.json 设置区域块MVC ...

  7. Oracle 创建用户,赋予指定表名/视图只读权限

    步骤指南 创建用户 格式:; 语法:create user 用户名 identified by 密码; 注:密码不行的话,前后加(单引号):' create user TEST identified ...

  8. 设置POP3/SMTP协议 手机绑定邮箱

    例如设置企业邮箱 一.设置POP3/SMTP协议,意思是代收邮件致本地POP3接收邮件服务器:pop.qiye.qq.comSMTP发送邮件服务器:smtp.qiye.qq.com二.设置IMAP/S ...

  9. Linux日志中如何查找关键字及其前后的信息

    在日常工作中,我们经常需要查看日志,比如可以通过 tail 命令实时查看日志,也可以通过 cat 等命令查看日志信息. 但现在我们要讨论的是,如何从日志中通过关键字过滤出我们想要的内容,方法有多种,今 ...

  10. 精通awk系列(5):BEGIN和END语句块

    回到: Linux系列文章 Shell系列文章 Awk系列文章 BEGIN和END语句块 awk的所有代码(目前这么认为)都是写在语句块中的. 例如: awk '{print $0}' a.txt a ...