1.哈希表:
(1)说哈希表之前不得说一下算法,我们都知道评价一个好的算法主要要从时间与空间复杂度来进行衡量。
时间复杂度就是执行算法所需要的时间,而空间付再度就是该算法所占的内存空间。两者均体现了计算机的资源的概念。毋庸置疑,对于一个数组我们都清楚,查找一个元素只要知道索引位置就可以了,因此,时间复杂度为O(1),然而对于一个链表其时间复杂度为O(n)。
(2)理想的情况就是不需要比较一次就能得到所查的记录,换言之,在记录的存储位置与他的关键字k之间建立一个确定的对应关系f,使得每一个关键字和结构中的一个位置唯一的对应,即f(k)。此时,称f为哈希函数。用该函数建的表为哈希表。
(3)几个基本概念:
冲突:不同关键字得到相同而的哈希值。
散列:散列函数:将数据的hashCode映射到表中的位置,这一映射过程叫做哈希造表或散列,此过程不需给出冲突解决方案。
好的散列函数的2个必备条件:1,快捷,在O(1)时间内运行;2,均匀的分布hashCode,填充概率相同。
哈希地址:根据关键字所得到的记录的存储位置。
冲突解决方案:当一个新项散列到已经被占据的散列表中的位置时,被告之发生冲突,解决方案用于确定新项可以插入散列表中未被占据的位置。
解决冲突主要的主要方法:开放寻址方法(寻找另外的空位);封闭寻址方法(吊挂另一种数据结构)
一般采用后者挂链表的方式。
再散列:当数据的容量大于散列表的容量的容量时,那么创建一张指定新容量的表,再将原来表中的数据映射到新表中。
2.关于HashMap的简单介绍:
HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
3.HashMap存储
HashMap<String ,int> hp = new HashMap<String,int>();
hp.put(“张三",20);
hp.put("李四",21);
4.HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置。
当程序执行 hp.put("张三" , 20); 时,系统将调用"张三"的 hashCode() 方法得到其 hashCode 值。每个对象都有 hashCode() 方法,都可通过该方法获得它的 hashCode 值。得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置。
参考put();方法的源码:
HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value 即可.
public V put(K key, V value){
// 如果 key 为 null,调用 putForNullKey 方法进行处理
if (key == null)
return putForNullKey(value);
//每个key.hashCode()返回一个hash值
int hash = hash(key.hashCode());
// 根据key.hashCode()的值来找记录的位置
int i = indexFor(hash, table.length);
// 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素
for (Entry<K,V> e = table[i]; e != null; e = e.next)
{
Object k;
// 找到指定 key 与需要将要存入的 key 相等 ,将
if (e.hash == hash && ((k = e.key) == key
|| key.equals(k)))
{
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
// 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry
modCount++;
// 将 key、value 添加到 i 索引处
addEntry(hash, key, value, i);
return null;
}
(1) Entry就是HashMap存储数据所用的类,相当于链表的节点;每个 Map.Entry 其实就是一个 key-value 对;我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。
(2)&按位取并的操作符,前提是length为2的n次幂。
public void addEntry(int hash, K key, V value, int bucketIndex){
// 获取指定 bucketIndex 索引处的 Entry
Entry<K,V> e = table[bucketIndex];
// 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
// 如果 Map 中的 key-value 对的数量超过了极限
if (size++ >= threshold)
// table 对象的长度扩充到 2 倍。
resize(2 * table.length);
}
系统总是将新添加的 Entry 对象放入 table 数组的 bucketIndex 索引处,如果 bucketIndex 索引处已经有了一个 Entry 对象,那新添加的 Entry 对象指向原有的 Entry 对象(产生一个 Entry 链)。
当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value。
参考一下get()方法的源码:
public V get(Object key){
// 如果 key 是 null,调用 getForNullKey 取出对应的 value
if (key == null)
return getForNullKey();
// 根据该 key 的 hashCode 值计算它的 hash 码
int hash = hash(key.hashCode());
// 直接取出 table 数组中指定索引处的值,
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
// 搜索该 Entry 链的下一个 Entr
e = e.next)
{
Object k;
// 如果该 Entry 的 key 与被搜索 key 相同
if (e.hash == hash && ((k = e.key) == key
|| key.equals(k)))
return e.value;
}
return null;
}
(1)HashMap 的每个 bucket 里只有一个 Entry 时,HashMap 可以根据索引、快速地取出该 bucket 里的 Entry;在发生“Hash 冲突”的情况下,单个 bucket 里存储的不是一个 Entry,而是一个 Entry 链,系统只能必须按顺序遍历每个 Entry,直到找到想搜索的 Entry 为止,如果恰好要搜索的 Entry 位于该 Entry 链的最末端(该 Entry 是最早放入该 bucket 中),那系统必须循环到最后才能找到该元素。
(2)如果 HashMap 中 Entry 的数量一直不会超过极限容量(capacity * load factor),HashMap 就无需调用 resize() 方法重新分配 table 数组,从而保证较好的性能。当然,开始就将初始容量设置太高可能会浪费空间(系统需要创建一个长度为 capacity 的 Entry 数组)。
相关推荐
### HashMap介绍和使用详解 #### 一、HashMap的数据结构 HashMap是Java集合框架的一个重要组成部分,它实现了Map接口,能够存储键值对映射。在Java编程语言中,最基本的数据结构有两种:数组和引用(模拟指针)。...
#### 实现类介绍 - **HashSet**:基于哈希表实现,提供高效的元素插入、删除和查找操作。元素无序,不能保证元素的顺序。 - **TreeSet**:基于红黑树实现,能够对元素进行排序,支持高效的范围查询。元素按自然顺序...
在Java编程中,HashMap是一个非常常用的集合类,用于存储键值对数据。然而,它存在一个重要的特性,那就是线程不安全。理解这个问题并找到解决方案是每个Java开发者必须掌握的知识。 HashMap线程不安全的原因主要...
这些集合类各自有着独特的特性和应用场景,下面将对它们进行详细介绍。 ### TreeMap `TreeMap`是基于红黑树(Red-Black tree)实现的Sorted Map(排序映射)。它实现了`Map`接口,并且提供了一些额外的方法,如`...
本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,虽然...
本文将详细介绍如何对HashMap进行排序以及相关的知识点。 **1. HashMap的特点** HashMap的核心特点是其内部通过哈希函数来计算元素的存储位置,这使得查找、插入和删除操作的时间复杂度在平均情况下为O(1)。然而,...
下面将详细介绍`HashMap`和`HashTable`之间的区别。 #### 一、线程安全性 - **HashTable**: 是线程安全的。它通过内部同步(synchronized)机制确保了多线程环境下的安全性。这意味着在多线程环境中,对`HashTable...
综上所述,《HASHMAP缓存.txt》文档不仅介绍了HashMap作为缓存的基本概念和实现方式,还涉及到了单例模式、线程安全、性能优化等高级主题,为开发者提供了丰富的技术细节和实用建议。在实际开发中,合理运用这些知识...
然而,在实际应用过程中,这两种数据结构有着本质的不同,下面将详细介绍这些差异。 #### 1. 历史背景及实现原理 - **Hashtable**:该类继承自`Dictionary`类,并且实现了`Map`接口。它最早出现在Java 1.0版本中,...
在本篇文章中,我们将详细介绍一个名为`hashMap`的工具类,该类被设计用于Adobe Flex应用程序中,旨在提供一种简单且高效的方法来处理键值对数据结构。通过深入分析该类的实现细节,我们能够更好地理解其内部机制,...
通常,这样的博客可能会介绍如何在ASP.NET代码中创建和使用HashMap和ArrayList,包括如何添加、删除和查找元素,以及它们在实际应用场景中的差异和选择原则。 标签中的“源码”意味着文章可能包含实际的代码示例,...
本文将详细介绍HashMap的底层原理,包括其内部实现结构、关键字段的作用、以及JDK 1.7和JDK 1.8版本的主要区别。 首先,HashMap是基于哈希表的Map接口非同步实现,它允许使用null值和null键,这意味着HashMap在设计...
本文将详细介绍如何利用 ibatis 框架通过 `HashMap` 来解决这一问题。 #### 1. 什么是 ibatis? ibatis 是一个基于 Java 的开源持久层框架,它提供了 SQL 映射功能,使得开发者可以通过 XML 文件或注解来定义 SQL ...
本文将详细介绍如何在Java WebService中使用`HashMap`来传递和读取数据。 #### WebService与HashMap的基本概念 1. **WebService**:一种开放的标准服务,通过HTTP协议进行数据传输,可以跨平台、跨语言地提供服务...
详细介绍了hashMap原理,值得一看,对于面试者有很大帮助
- "讲义"可能系统地介绍了HashMap的基础知识,如插入、查找和删除的步骤,以及HashMap与其他数据结构(如TreeMap)的区别。 通过深入研究这些资源,开发者可以更好地掌握HashMap的使用技巧,避免常见的性能问题,并...
在博文“HashMap通过对VALUE排序 源代码”中,作者可能详细介绍了如何实现上述方法,尤其是自定义Comparator来对HashMap的值进行排序。遗憾的是,由于没有提供具体的博客内容,我们无法给出更详细的源代码分析。不过...
在本文中,我们将详细介绍如何模拟Java的HashMap集合,使用数组和链表来实现Hash表的存储。我们将从基本概念开始,逐步深入到HashMap的实现细节中。 什么是HashMap? HashMap是一种基于散列表的数据结构,用于存储...
本篇将详细介绍如何使用JDOM解析XML文件,并将其内容存入HashMap中。 首先,我们需要了解JDOM的基本使用。JDOM的核心类包括`SAXBuilder`用于解析XML文档,`Document`表示整个XML文档,`Element`代表XML的元素节点,...
资源介绍:。1、此HashMap类采用java jdk中HashMap的实现方式。2、相比网站上发布过的hashtable之类的源码:。此HashMap寻址方法是拉链法.比开放寻址法对连续内存要求更低。哈希函数用的是java中String.hashCode()...