在Java中,HashMap是一种散列表,它存储键值对,并可以通过键进行快速检索。HashMap同样也是我们日常开发中使用非常广泛的数据结构之一,因此,了解HashMap的工作原理及手动实现HashMap是我们开发Java应用程序的必备技能之一。本文将会从多个方面对手写HashMap进行详细阐述,帮助读者全面了解HashMap的运作原理及具体实现。
一、HashMap的概述
HashMap是一个散列表,它是Java Collection Framework中的一部分。HashMap以键值对(Key-Value Pairs)的形式存储数据,Key可以通过hashCode()方法被哈希为一个整数,并被哈希表作为索引来保存数据的地址
HashMap的作用就是能够在O(1)的时间复杂度内实现增删改查。其中,增加操作put(),删除操作remove(),获取操作get(),都可以通过键直接进行访问,极大的提高了我们的开发效率。
二、HashMap的实现原理
HashMap的实现原理主要基于哈希表,每个元素都以Key-Value的形式保存在一个桶(bucket)中。当进行查找操作时,首先根据Key哈希为一个整数,然后根据这个整数映射到桶中,从而找到Key所在的位置。
一、哈希函数
哈希函数是HashMap中的一个重要概念,哈希函数将传入的Key转换为一个哈希码(hashCode),通过哈希码在底层数组中进行查找。哈希函数映射的哈希码越分布越均匀,则冲突的概率也就越小,HashMap的效率也就越高。
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
我们可以看到,hashCode()函数返回一个int类型的哈希码,这个哈希码由Java提供的一个特定的公式生成,该公式的目的是让生成的哈希码分布得越均匀越好。
二、哈希冲突的解决方法
当不同的Key通过哈希函数产生的哈希码相同时,就会发生哈希冲突。哈希冲突时,需要使用链表或红黑树等数据结构来解决,这也是HashMap为什么能够在时间复杂度为O(1)内实现高效增删改查的原因。
HashMap中链表的长度阈值为8,如果同一个桶内链表长度超过了8,则该链表会转换为红黑树,以提高查找效率。如果删除元素后,链表长度小于等于6,则将红黑树转换为链表。
三、手写HashMap的实现
为了直观地展示HashMap的工作原理,我们接下来将手动实现一个简单的HashMap。
一、初始化HashMap
我们首先定义一个简单的HashMap类,它包含一个Node数组和一个长度变量size:
public class MyHashMap {
private Node[] arr;
private int size;
}
在构造函数中,我们需要对Node数组进行初始化,这里我们设置数组大小为10:
public MyHashMap() {
arr = new Node[10];
}
二、实现put方法
put方法是向HashMap中添加Key-Value对的方法。我们需要通过Key的哈希值来确定该元素在Node数组中的位置,并且,当哈希冲突时,需要使用链表将其保存。put方法的实现过程如下:
public void put(int key, int value) {
int index = key % arr.length;
if (arr[index] == null) {
arr[index] = new Node(key, value);
size++;
} else {
Node node = arr[index];
while (node.next != null) {
if (node.next.key == key) {
node.next.value = value;
return;
}
node = node.next;
}
if (node.key == key) {
node.value = value;
} else {
node.next = new Node(key, value);
size++;
}
}
}
可以看到,我们首先通过Key计算出其哈希值,然后用哈希值来确定该key在Node数组中的位置。如果该位置为空,则直接在该位置插入一个新的Node,如果该位置不为空,则需要遍历链表来查找该Key,如果找到,则更新其Value值,否则,在该链表尾部添加一个新的Node节点。
三、实现get方法
get方法是获取HashMap中指定Key对应的Value值的方法。与put方法类似,get方法也需要通过Key的哈希值来确定该元素在Node数组中的位置。get方法的实现过程如下:
public int get(int key) {
int index = key % arr.length;
Node node = arr[index];
while (node != null) {
if (node.key == key) {
return node.value;
}
node = node.next;
}
return -1;
}
可以看到,我们通过Key计算出其哈希值,然后用哈希值来确定该key在Node数组中的位置。如果该位置为空,则该Key不存在于HashMap中,返回-1;否则,遍历链表来查找该Key,如果找到,则返回对应的Value值。
四、HashMap的使用
手写的MyHashMap虽然不如Java原生的HashMap强大,但是其原理和简洁的代码十分直观,值得用于学习和理解HashMap的工作原理。下面我们来看一下如何使用Java原生的HashMap:
HashMap<String, String> map = new HashMap<>();
map.put("Key1", "Value1");
map.put("Key2", "Value2);
String value1 = map.get("Key1");
String value2 = map.get("Key2");
如上述代码所示,我们可以轻松地使用Java原生的HashMap进行操作,并可以在一次代码调用中实现快速地增删改查。
总结
本文以手写HashMap为中心,详细介绍了HashMap的工作原理及具体实现。HashMap作为一个重要的数据结构,能够在Java开发中发挥重要作用。如果不仅限于Java开发,类似HashMap的数据结构在其他领域同样具有重要的意义。了解HashMap以及其他相关数据结构的工作原理及实现,将有助于我们更好地理解算法原理,提高开发效率。
原创文章,作者:JKNNW,如若转载,请注明出处:https://www.506064.com/n/332767.html