面试专题 HashMap如何在Java中工作

通过优锐课的java学习分享中,了解了企业的面试题型,分享给大家学习。

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;
 }

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

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

我希望本文能阐明麻烦的HashMap内部机制。 学习愉快!

喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
?> 如果你对java技术很感兴趣也可以交流学习,共同学习进步。?
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

文章写道这里,欢迎完善交流。最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java干货

原文地址:https://blog.51cto.com/14634606/2469630

时间: 2024-10-10 21:16:02

面试专题 HashMap如何在Java中工作的相关文章

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

如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录就会删除一条最老的记录. import java.util.LinkedHashMap; import java.util.Map; public class MaxSizeHashMap<K, V> extends LinkedHashMap<K, V> { private fina

如何在Java中执行Hive命令或HiveQL

这里所说的在Java中执行Hive命令或HiveQL并不是指Hive Client通过JDBC的方式连接HiveServer(or HiveServer2)执行查询,而是简单的在部署了HiveServer的服务器上执行Hive命令.当然这是一个简单的事情,平常我们通过Hive做简单的数据分析实验的时候,都是直接进入Hive执行HiveQL,那我们为什么还要在程序中执行呢? 这里涉及到了一个问题,通过进入Hive执行HiveQL,我们只能将分析结果打印到屏幕或是存入临时表,那如果我们想吧分析结果写

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

并发编程是Java语言的重要特性之一,"如何在Java中实现线程"是学习并发编程的入门知识,也是Java工程师面试必备的基础知识.本文从线程说起,然后用代码说明如何在Java中实现线程. 一.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,也可以使用多线程对运算密集型任务提速.如果使用得当,线程可以有效地降低程序的开发和运维成本,同时能够提升程序的性能. 二.线程和进程有什么区别? 线程是进程的子集,

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

很早之前写过一篇介绍sikuli的文章.本文简单介绍如何在java中使用sikuli进自动化测试. 图形脚本语言sikuli sikuli IDE可以完成常见的单击.右击.移动到.拖动等鼠标操作,java引用sikuli-script.jar同样可以执行这些常见的鼠标操作,因此即可方便的编写java实现识别图片并模拟点击/拖动目标控件. sikuli-script.jar:http://download.csdn.net/download/hqd1986/4557974 将sikuli-scri

Java基础---如何在Java中注释(十)

如何在Java中使用注释 在编写程序时,经常需要添加一些注释,用以描述某段代码的作用. 一般来说,对于一份规范的程序源代码而言,注释应该占到源代码的 1/3 以上.因此,注释是程序源代码的重要组成部分,一定要加以重视哦! Java 中注释有三种类型:单行注释.多行注释.文档注释 运行结果: 看:被注释的代码块在程序运行时是不会被执行的~~ 我们可以通过 javadoc 命令从文档注释中提取内容,生成程序的 API 帮助文档. 打开首页,查看下生成的 API 文档 PS:使用文档注释时还可以使用

如何在Java中调用Python代码

有时候,我们会碰到这样的问题:与A同学合作写代码,A同学只会写Python,而不会Java, 而你只会写Java并不擅长Python,并且发现难以用Java来重写对方的代码,这时,就不得不想方设法“调用对方的代码”. 下面我将举一些简单的小例子,借此说明:如何在Java中调用Python代码. 看懂这篇文章只需要具备: 熟悉Java的基本语法 懂一点点Python 主要内容如下: 什么是Jython? 一个HelloPython程序 在Jvm中执行Python脚本 仅在Java中调用Python

我说精通字符串,面试官竟然问我 Java 中的 String 有没有长度限制?

String 是 Java 中很重要的一个数据类型,除了基本数据类型以外,String 是被使用的最广泛的了,但是,关于 String,其实还是有很多东西容易被忽略的. 就如本文我们要讨论的问题:Java 中的 String 有没有长度限制? 这个问题要分两个阶段看,分别是编译期和运行期.不同的时期限制不一样. 01 编译期 首先,我们先来合理的推断一下,当我们在代码中使用 String s = ""; 的形式来定义 String 对象的时候,"" 中字符的个数有没

慕课网-安卓工程师初养成-2-12 如何在Java中使用注释

来源:http://www.imooc.com/code/1274 在编写程序时,经常需要添加一些注释,用以描述某段代码的作用. 一般来说,对于一份规范的程序源代码而言,注释应该占到源代码的 1/3 以上.因此,注释是程序源代码的重要组成部分,一定要加以重视哦! Java 中注释有三种类型:单行注释.多行注释.文档注释 运行结果: 看:被注释的代码块在程序运行时是不会被执行的~~ 我们可以通过 javadoc 命令从文档注释中提取内容,生成程序的 API 帮助文档. 打开首页,查看下生成的 AP

七、如何在Java中高效检查一个数组是否含有一个值

如何检查一个数组(非排序的)是否包含特定的值.这是个非常有用或经常被在Java中使用.这是个在Stack Overflow中高得票的问题.在已经高得票的答案中,有许多不同的处理方法,但是时间的复杂度非常不同.在下面,我将会展示每种方法的时间花费. 一.四种不同的方法去检查一个数组包含特定的值 1) 用List public static boolean useList(String[] arr, String targetValue) { return Arrays.asList(arr).co