Java写哈希表的完整实例代码

 更新时间:2026年03月17日 08:50:39   作者:洛洛书  
Java中的哈希表是数据结构中的一个重要组成部分,用于高效存储和查找数据,这篇文章主要介绍了Java写哈希表的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、什么叫哈希表(HashMap)?

哈希表的实质是一种结合数组和链表优势的复合数据结构,类似于 Java 官方提供的 HashMap 集合类,不同的是它是我们基于哈希函数 + 链表解决冲突的思想手动实现的底层存储结构。因为其本质是 “数组 + 链表” 的组合存储逻辑,而非原生的数据类型,所以需要通过定义哈希函数、链表节点、核心操作方法来赋予其可操作的能力,只有被实例化为对象时,才能完成键值对的增删查等操作。

哈希表以数组为底层基础容器,通过哈希函数将键(Key)映射到数组的指定索引位置;当多个键映射到同一索引时(哈希冲突),则通过链表将这些冲突的键值对串联存储,既保留了数组随机访问的高效性,又解决了数组固定长度、冲突存储的问题。

二、定义自定义 HashMap 的方法?

(一)先定义核心组件

1. 节点类(Node)

访问修饰符 + class + 类名

节点类是哈希表中存储键值对的最小单位,需要定义存储键、值的属性,以及指向下一个节点的引用(用于链表串联)。

(1)节点类的属性:

理解:节点的属性可以看成存储单个键值对的核心特征(比如键 key、值 value,以及链表中下一个节点的引用 next)。定义格式:访问修饰符 + 数据类型 + 属性名

(2)节点类的构造方法:

理解:用于初始化节点的键和值,给 next 引用赋默认值。

定义格式:访问修饰符 + 类名(参数类型 + 参数名,…){属性赋值…}

2. 链表类(LinkList)

访问修饰符 + class + 类名

链表类用于解决哈希冲突,存储数组同一索引下的所有冲突键值对,需要定义链表的头节点属性,以及添加、查询键值对的方法。

(1)链表类的属性:

理解:链表的属性是其核心特征(比如头节点 head,作为链表遍历的起点)。定义格式:访问修饰符 + 数据类型 + 属性名

(2)链表类的方法:

理解:链表的方法是其核心行为(比如添加 / 覆盖键值对、根据键查询值)。

定义格式:访问修饰符 + 返回值类型 + 方法名(参数类型 + 参数名,…){方法体…}

3. 哈希表主类(MyHashMap)

访问修饰符 + class + 类名

哈希表主类是对外提供操作接口的核心类,需要定义存储链表的数组、数组默认长度等属性,以及构造方法、哈希函数、put/get 核心方法。

(1)哈希表的属性:

理解:哈希表的属性是其核心特征(比如存储链表的数组 linkLists、数组默认长度 len)。

定义格式:访问修饰符 + 数据类型 + 属性名

(2)哈希表的方法:

理解:哈希表的方法是其核心行为(比如哈希函数 hash ()、存储键值对 put ()、查询值 get ())。

定义格式:访问修饰符 + 返回值类型 + 方法名(参数类型 + 参数名,…){方法体…}

class Node {
    Object key;
    Object value;
    Node next;

    // 构造方法:初始化键值对,next默认null
    public Node(Object key, Object value) {
        this.key = key;
        this.value = value;
        this.next = null;
    }
}
class LinkList {
    // 链表头节点
    private Node head;

    // 添加/覆盖键值对:存在相同key则覆盖value,不存在则新增节点
    public void add(Object key, Object value) {
        // 头节点为空,直接创建新节点作为头节点
        if (head == null) {
            head = new Node(key, value);
            return;
        }

        // 遍历链表,查找是否存在相同key
        Node current = head;
        while (current != null) {
            // key相等(处理null key),覆盖value
            if (equals(key, current.key)) {
                current.value = value;
                return;
            }
            // 到链表尾部,退出循环
            if (current.next == null) {
                break;
            }
            current = current.next;
        }

        // 无相同key,在链表尾部新增节点
        current.next = new Node(key, value);
    }

    // 根据key获取对应value,无则返回null
    public Object get(Object key) {
        Node current = head;
        while (current != null) {
            // 匹配key(处理null key)
            if (equals(key, current.key)) {
                return current.value;
            }
            current = current.next;
        }
        // 未找到对应key
        return null;
    }

    // 辅助方法:判断两个key是否相等(处理null值)
    private boolean equals(Object k1, Object k2) {
        if (k1 == null && k2 == null) {
            return true;
        }
        if (k1 == null || k2 == null) {
            return false;
        }
        return k1.equals(k2);
    }
}
public class MyHashMap {
    //定义保存链表的数组
    public LinkList[] linkLists;
    public static int len = 16;

    //自定义长度
    public MyHashMap(int len) {
        linkLists = new LinkList[len];
        //初始化数组,每个位置都创建空链表
        for(int i=0;i<len;i++){
            linkLists[i] = new LinkList();
        }
    }

    //默认长度
    public MyHashMap() {
        this(len);
    }

    //put数据:存储键值对,键重复则覆盖值
    public void put(Object key, Object value) {
        //根据当前key,利用哈希函数计算位置
        int index = hash(key);
        //取出对应链表,保存键值对(处理重复键覆盖)
        linkLists[index].add(key, value);
    }

    //get 取出数据:根据key获取对应value,无则返回null
    public Object get(Object key){
        int index = hash(key);
        return linkLists[index].get(key);
    }

    //哈希函数(散列函数):计算key在数组中的索引,处理负数哈希值
    public int hash(Object key) {
        if (key == null) {
            return 0; // null键固定放在索引0位置
        }
        int hashCode = key.hashCode();
        // 处理负数哈希值,保证索引非负
        return (hashCode & 0x7FFFFFFF) % linkLists.length;
    }

    public static void main(String[] args) {
        MyHashMap hm = new MyHashMap();
        hm.put("a",10);
        hm.put("a",20); // 重复key,覆盖值
        hm.put("c",null);
        hm.put(null, 99); 

        System.out.println(hm.get("a"));  
        System.out.println(hm.get("c"));  
        System.out.println(hm.get(null)); 
        System.out.println(hm.get("d"));  
    }
}

三、自定义 HashMap 核心逻辑解析

1. 哈希函数的作用

(1)核心功能:将任意类型的键(Key)映射为数组的索引,公式为 (key.hashCode() & 0x7FFFFFFF) % 数组长度;(2)关键处理:

null 键特殊处理:固定映射到索引 0 位置,符合 Java 官方 HashMap 的设计;

负数哈希值处理:通过 & 0x7FFFFFFF 将哈希值转为正数,避免索引为负数的异常。

2. put 方法核心流程

(1)调用哈希函数计算键对应的数组索引;(2)取出该索引位置的链表,调用链表的 add 方法;(3)链表 add 方法逻辑:

若链表为空,直接创建新节点作为头节点;

若链表非空,遍历查找是否有相同 key,有则覆盖 value,无则在链表尾部新增节点。

3. get 方法核心流程

(1)调用哈希函数计算键对应的数组索引;(2)取出该索引位置的链表,调用链表的 get 方法;(3)链表 get 方法逻辑:遍历链表匹配 key,匹配成功则返回对应 value,无匹配则返回 null。

四、补充说明

  1. 哈希冲突解决:本文采用链地址法(链表)解决哈希冲突,这是 Java 官方 HashMap 的核心实现方式(JDK1.8 后,当链表长度超过阈值会转为红黑树,本文简化为纯链表);
  2. 边界处理:兼容 null 键和 null 值的存储、查询,处理了哈希值为负数的异常场景,保证索引合法性;
  3. 核心特性:实现了 HashMap 最核心的 “键唯一、值可重复、键重复覆盖值” 的特性,与官方 HashMap 行为一致。

到此这篇关于Java写哈希表的文章就介绍到这了,更多相关Java写哈希表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用@Autowired注解引入server服务层方法时报错的解决

    使用@Autowired注解引入server服务层方法时报错的解决

    这篇文章主要介绍了使用@Autowired注解引入server服务层方法时报错的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • java新人基础入门之递归调用

    java新人基础入门之递归调用

    这篇文章主要给大家介绍了关于java新人基础入门之递归调用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • java实现文件切片上传百度云+断点续传的方法

    java实现文件切片上传百度云+断点续传的方法

    文件续传在很多地方都可以用的到,本文主要介绍了java实现文件切片上传百度云+断点续传的方法, 文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java中的Phaser并发阶段器详解

    Java中的Phaser并发阶段器详解

    这篇文章主要介绍了Java中的Phaser并发阶段器详解,Phaser由JDK1.7提出,是一个复杂强大的同步辅助类,是对同步工具类CountDownLatch和CyclicBarrier的综合升级,能够支持分阶段实现等待的业务场景,需要的朋友可以参考下
    2023-12-12
  • Java KindEditor粘贴图片自动上传到服务器功能实现

    Java KindEditor粘贴图片自动上传到服务器功能实现

    这篇文章主要介绍了Java KindEditor粘贴图片自动上传到服务器功能实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Java实现数据库连接的最详细教程分享

    Java实现数据库连接的最详细教程分享

    JDBC,Java Database Connectivity,即Java数据库连接,是 Java 中的一套和数据库进行交互的API,本文就来讲讲Java如何利用JDBC实现数据库的连接吧
    2023-05-05
  • Springboot项目由JDK8升级至JDK17详细教程

    Springboot项目由JDK8升级至JDK17详细教程

    这篇文章主要为大家详细介绍了Springboot项目如何由JDK8升级至JDK17,本文为大家整理了全过程的详细步骤,有需要的小伙伴可以参考一下
    2025-06-06
  • SpringMVC 通过ajax 前后端数据交互的实现方法

    SpringMVC 通过ajax 前后端数据交互的实现方法

    这篇文章主要介绍了SpringMVC 通过ajax 前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-04-04
  • HashMap链表与红黑树转换详解

    HashMap链表与红黑树转换详解

    这篇文章主要介绍了HashMap链表与红黑树转换详解,HashMap是Java中的一种数据结构,它实现了Map接口,提供了键值对的存储和检索功能,它基于哈希表的原理,通过将键映射到哈希表中的位置来存储和获取值,从而实现了快速的查找和插入操作,需要的朋友可以参考下
    2023-11-11
  • Java模拟栈和队列数据结构的基本示例讲解

    Java模拟栈和队列数据结构的基本示例讲解

    这篇文章主要介绍了Java模拟栈和队列数据结构的基本示例,栈的后进先出和队列的先进先出是数据结构中最基础的知识,本文则又对Java实现栈和队列结构的方法进行了细分,需要的朋友可以参考下
    2016-04-04

最新评论