HashMap是如何存放对象
在JAVA中最基本的结构有两种,一种是数组,另一种就是模拟指针,也就是我们说的引用。首先可以把HashMap内部的存储结构理解为一个数组,任一一个对象放进来,通过对象Key的hashCode方法,得到对象Key哈稀后的一个整数值,然后根据对象计算的hashCode通过某种策略计算出它要放置的数组中的位置。具体按什么策略来决定放置的位置呢?比较容易能想到的就是通过hashCode与数组长度进行的取模 (hashCode % array.length),但取模运算的效率比较低,在HashMap中的实现是:
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
将hashCode值与数组长度减1的值做了个与运算,计算出的结果就是放置数组的索引(因为这一实现,又引出了另一个有意思的话题"HashMap的空间的大小是如何影响自身效率的",见第二部分)。那现在对HashMap的存放对象有一个初步的认识,存放对象是通过数组来实现,存的时候对象存在哪,取的时候去哪取,都是通过对象KEY的HashCode值来计算存储的数组索引,从而实现读与取。如果H只是通过目前分析的访求来存放对象的话,肯定是不行的,因为不同对象的hashCode值很可能是一样的,其碰撞概率并不低,如字符串"a"与值为97的Integer对象的hashCode值就一样。那这样的问题H是如何解决的呢?上面的分析基础还是很有价值的,H的实现也是在之前分析基础之上,进行了改良。还是通过数组来存,但存的不是单一对象,而是数组中的每个对象都是一个链表结构,为了方便理解,图示:
通过上图,可以很直观的理解H的存储结构,H查找对象分两步走,一通过对应的hashCode确定对象应该放置的数组位置,第二步则是在数组对应的链表进行遍历,通过key的equals方法来找到链表中对应的对象(不存在返回NULL)。
如何定义HashMap的大小
HashMap会在空间占用达到阀值时,会触发resize()操作,resize将会对现有数组进行扩容,HashMap里的所有对象都需要重要进行hash计算,然后把对象放置到新的位置,这将的操作是应该尽量避免的,存储大量对象的时候,更是如此。HashMap
假设有1000个对象要放到MAP中进行存储,假设我们不希望对象在PUT的过程中HashMap发生resize操作,那该定义多大的才保险?1000?NO! HashMap会在数组使用数达到一个阀值的时候进行resize操作,阀值的定义是这样的:
threshold = (int)(capacity * loadFactor);
HashMap中的loadFactor默认为0.75,所以如果定义一个size为1000的HashMap,当数组占用超过750,就会触发resize操作。所以如果要存放1000个对象,可以假设在极端情况下,这1000个对象的hashCode都不一样,那HashMap需要至少定义1334(1000/0.75),才能确保存放1000个对象的情况下,一定不会出现resize操作。
除了上述分析的,定义合适的大小避免HashMap触发resize操作外,HashMap的大小还会影响其内部数组的使用率。HashMap是通过对象的hashCode值来决定放置数组的位置,代码如下:
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
通过代码可以发现,当数组大小被定义为2的次方大小,数组的所有位置才都会有命中的可能,如大小为8时,数组的8个位置都可以命中,如大小改为7,那数组的最后一位(即下标为6)的位置,不会有对象落在这个位置上。
相关推荐
在深入探讨HashMap的实现原理之前,我们需要了解两个关键的接口方法:`hashCode()`和`equals()`。 根据《Effective JAVA》的建议,当重写`equals()`方法时,也应重写`hashCode()`方法。这是因为在HashMap中,`...
下面我们将对HashMap的resize()方法进行源码解读,了解其扩容机制和原理。 一、resize()方法概述 resize()方法的主要功能是扩容HashMap的容量,以便存储更多的键值对。该方法分为两部分:创建新数组和将旧数组元素...
HashMap 的存储实现可以通过查看其 put(K key, V value) 方法的源代码来了解。该方法首先判断 key 是否为 null,然后根据 key 的 hashCode 值计算 Hash 值,接着搜索指定 hash 值在对应 table 中的索引,如果 i 索引...
《HashMap 实例解析与关联数据结构对比》 HashMap 是 Java 中常用的一种数据结构,属于 Java.util 包下的类,它是基于哈希表实现的。...了解这些基本数据结构的特点和用法,有助于我们在实际编程中做出明智的选择。
在这个压缩包“HashMap类.rar”中,包含的是易语言版本的HashMap类源码,这将有助于我们了解易语言如何实现类似Java中HashMap的功能。 HashMap类的核心概念和特性包括以下几点: 1. **哈希表**:HashMap使用哈希表...
3. **负载因子**:HashMap有一个名为`loadFactor`的属性,表示在达到当前容量的多少比例时,HashMap会自动扩容。默认负载因子是0.75,这意味着当填满75%的桶后,HashMap会自动扩大其内部数组的大小,以保持性能。 4...
这个精简版的HashMap Demo可以帮助初学者理解HashMap的基本工作原理,通过实际代码了解其内部机制。在学习过程中,可以重点关注哈希函数的设计、链表的插入与查找以及扩容的实现,这些都是HashMap性能的关键因素。...
### Hashtable与HashMap的区别 在Java编程语言中,`Hashtable`和`HashMap`是两种非常重要的数据结构,它们都属于`Map`接口...同时,MVC模式、SQL查询语言的不同以及JSP与Servlet的关系也是开发者应该了解的重要概念。
通过以上分析,我们可以了解到实现一个自定义的HashMap涉及许多细节和技巧,包括哈希函数的设计、冲突解决策略的选择、以及性能优化等。在实际编程中,理解这些概念有助于我们更好地使用和定制HashMap,满足特定需求...
在Java编程语言中,`HashMap`是`...在学习和使用`HashMap`时,不仅要掌握其基本用法,还要了解其内部工作原理,包括哈希函数、哈希冲突的解决策略(开放寻址法或链地址法),以及如何调整容量和负载因子以优化性能。
哈希映射(HashMap)是Java编程语言中一个非常重要的数据结构,主要用于...了解并熟练掌握HashMap的原理和使用,对于提升Java程序的性能至关重要。在实际开发中,根据具体需求选择合适的数据结构是优化代码性能的关键。
### Hashtable和HashMap的区别 ...总之,了解`Hashtable`和`HashMap`之间的差异对于正确选择合适的数据结构至关重要。通过权衡线程安全性和性能需求,可以更有效地利用这些数据结构来解决实际问题。
根据提供的内容,我们可以了解到遍历`HashMap`主要有两种方式:使用`keySet()`方法和使用`entrySet()`方法。 1. **使用keySet()方法** ```java Map map = new HashMap(); Iterator iter = map.keySet()....
HashMap是Java编程语言中一种非常重要的数据结构,它属于Java集合框架的一部分,是基于哈希表实现的。...同时,了解并掌握HashMap的这些基本操作对于Java开发者来说是非常重要的,因为它们在各种场景下都有广泛的应用。
### HashMap原理详解 #### 一、HashMap简介与...通过对HashMap的工作原理及其内部实现细节的深入了解,开发者不仅能够更好地利用这一强大的数据结构,还能在遇到性能瓶颈时采取针对性的优化措施,提升系统的整体表现。
该项目的主要目的是熟悉Java集合框架中的`HashMap`类,并了解如何利用它来存储、管理和检索数据。此外,我们还将学习如何使用`Scanner`类从键盘接收用户输入。 #### 二、实验需求分析 根据题目要求,我们需要完成...
首先,我们需要了解HashMap的基本概念。HashMap是一个散列容器,内部通过数组加链表的方式实现。每个键值对由一个Entry对象表示,这些Entry对象存储在一个数组中。当两个键通过哈希函数计算出相同的索引时,它们会被...
相反,如果你的应用程序需要处理多线程并发问题,并且对线程安全性有严格要求,那么 `Hashtable` 或者通过 `Collections.synchronizedMap()` 包装后的 `HashMap` 更适合。了解这些区别有助于开发者在实际开发过程中...