摘要:经过上述讨论,我们发现,哈希查找的时间复杂度最小没有冲突是二是什么首先是中的一个接口。在中,有很多类实现了接口,就是其中的一个三是什么是一个实现了接口的基于哈希表的类。
我们要想知道HashMap是什么就先要了解Hash和Map是什么
一、Hash是什么
① 哈希查找是一种数据结构中用于 查找 的算法,相比于其他查找算法,他的时间复杂度更
低,所以在实际应用中大量采取了哈希表的方式,Hashmap就是java内置的哈希查找的方法
② 哈希函数的基本思想: 将记录的存储地址和关键字之间建立一个确定的对应关系。这样,当想查找某条记录时,我们根据记录的关键字就可以得到它的存储地址,进而快速判断这条记录是否存在,存储在哪里。
③负载因子:负载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。如果负载因子越大,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小,那么散列表的数据将过于稀疏,对空间造成严重浪费。hashmap默认负载因子为0.75,一般情况下我们是无需修改的。
④ 哈希函数的缺陷+改进方式: 在哈希存储中,不同的关键字可能映射到了相同的地址,这就叫产生冲突,我们必须相处冲突处理的方法。当然,前辈们已经相处了各种各样的方法,我在这里先不做深究。
⑤ 经过上述讨论,我们发现,哈希查找的时间复杂度最小(没有冲突)是O(1)
二、Map是什么
首先Map是java中的一个接口。它是java中的一种重要的数据结构。
Map是从键(关键字)到值(记录)的映射,键不允许重复,每个键最多能映射一个值。
在java中,有很多类实现了Map接口,HashMap就是其中的一个
三、Hashmap是什么
HashMap是一个实现了Map接口的基于哈希表的类 。
也就是说,HashMap既有map的键值对特点,也有哈希表的特点
简单点说,利用HashMap类:
查找时,给出一个关键字key,我们可以根据hash算法计算出key-value的存储位置然后取出value
存储时,我们根据哈希算法计算出该键值对应该存储的位置,将其存进去。
也就是说,当没有冲突时,HashMap存取的时间复杂度为O(1)
这是HashMap类的部分代码(部分数据域和构造函数)
public class HashMapextends AbstractMap implements Map , Cloneable, Serializable { static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 默认初始容量 static final int MAXIMUM_CAPACITY = 1 << 30; //HashMap的最大容量 static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认负载因子0.75 static final int TREEIFY_THRESHOLD = 8; //当某条链表中元素的个数大于8时//将转变为红黑树 transient Node [] table; // table数组,每一个元素都是一个Node对象,接下来会介绍Node是什么 transient Set > entrySet; transient int size; //记录哈希表中的键值对个数 int threshold; //阈值,即当table中元素个数大于这个值就要resize() final float loadFactor; //加载因子
HashMap有四种构造函数
①第一种 允许用户自己决定初始容量和加载因子,但这个初始容量不一定是HashMap真正的初始容量,下文会对此进行解释
public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0)//初始容量不可以小于0 throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY;//不可以大于最大容量 if (loadFactor <= 0 ||Float.isNaN(loadFactor))//加载因子不可以小于0 throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity); }
在构造函数中,我们可以看到,阈值利用tableSizeFor进行了计算,而此时的阈值并不是真正的阈值,是数组的容量,我们也会发现其实在构造函数中并没有给table分配内存,这是因为在插入键值对时,put函数会判断table是否为null,如果是那么用resize()函数为其分配空间并计算真正的阈值
其他三种构造函数
public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } public HashMap(Map extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); }
}
【小贴士】
1.AbstractMap抽象类是什么?
AbstractMap抽象类实现了Map接口的大部分方法,让HashMap继承它减少了实现Map接口的工作量。那它为什么是抽象类呢,因为它有唯一的一个抽象方法
Public abstract Set
当然在HashMap中有很多方法对AbstractMap的方法进行了覆盖
下一节:HashMap的数据结构
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69987.html
摘要:当一个值中要存储到的时候会根据的值来计算出他的,通过哈希来确认到数组的位置,如果发生哈希碰撞就以链表的形式存储在源码分析中解释过,但是这样如果链表过长来的话,会把这个链表转换成红黑树来存储。 正文开始 注:JDK版本为1.8 HashMap1.8和1.8之前的源码差别很大 目录 简介 数据结构 类结构 属性 构造方法 增加 删除 修改 总结 1.HashMap简介 H...
摘要:的工作原理是近年来常见的面试题。让我们再来看看这些问题设计哪些知识点的概念中解决碰撞的方法和的应用,以及它们在中的重要性不可变对象的好处多线程的条件竞争重新调整的大小总结的工作原理基于原理,我们通过和方法储存和获取对象。 HashMap 的工作原理是近年来常见的 Java 面试题。几乎每个 Java 程序员都知道 HashMap,都知道哪里要用 HashMap,知道Hashtable和...
摘要:根据的重新计算值。如果这两个的通过比较返回,新添加的将覆盖集合中原有的,但不会覆盖。如果这两个的通过比较返回,新添加的将与集合中原有形成链,而且新添加的位于链的头部具体说明继续看方法的说明。 关于hashCode hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的. 1.hashcode是用来...
摘要:为了解决这个问题设计了一个阈值,其值为容量的,当所用容量超过了阈值后,就会自动扩充其容量。如果条件竞争发生了,那么就会产生死循环了。 由于HashMap的容量是有限的,如果HashMap中的数组的容量很小,假如只有2个,那么如果要放进10个keys的话,碰撞就会非常频繁,此时一个O(1)的查找算法,就变成了链表遍历,性能变成了O(n),这是Hash表的缺陷。 为了解决这个问题,Hash...
摘要:在二叉查找树强制一般要求以外,对于任何有效的红黑树增加了如下的额外要求节点是红色或黑色。红黑树有哪些应用场景内核和系统调用实现中使用的完全公平调度程序使用红黑树。 前言 这篇文章是记录自己分析 Java 8 的 HashMap 源码时遇到的疑问和总结,在分析的过程中笔者把遇到的问题都记录下来,然后逐一击破,如果有错误的地方,希望读者可以指正,笔者感激不尽。 疑问与解答 什么是 initia...
阅读 512·2021-10-19 11:45
阅读 1290·2021-09-30 09:48
阅读 1426·2021-08-16 10:56
阅读 693·2021-07-26 23:38
阅读 3177·2019-08-30 13:15
阅读 2552·2019-08-30 12:45
阅读 1768·2019-08-29 12:14
阅读 1969·2019-08-26 18:42