自定义实现Java的HashMap集合

一、目的

自定义实现Java的散列表HashMap。

核心:

1、每个Java对象都有hashcode()方法返回哈希码。

2、把哈希码处理后,对一个数组容量取余数,获得存储下标。

3、如果多个元素的下标相同,把这些元素用链表存放在一起。

二、主要代码

(一)元素节点的抽象类Entry

java 复制代码
/**
 * 
 * @version 1.0.0
 * <p>
 * date: 2026/4/19
 **/
public class Entry<K, V> {
    // 键名
    private K key;
    // 值
    private V value;
    // 指向其他相同下标的元素
    private Entry<K, V> next;

    public Entry(K key, V value, Entry<K, V> next) {
        this.key = key;
        this.value = value;
        this.next = next;
    }

    public K getKey() {
        return key;
    }

    public void setKey(K key) {
        this.key = key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }

    public Entry<K, V> getNext() {
        return next;
    }

    public void setNext(Entry<K, V> next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Entry{" +
                "key=" + key +
                ", value=" + value +
                ", next=" + next +
                '}';
    }
}

(二)KHashMap类

名字是KHashMap,和Java官方的HashMap区分。

java 复制代码
/**
 * @author 
 * @version 1.0.0
 * <p>
 * date: 2026/4/19
 **/
public class KHashMap<K, V> {

    private Object[] entries = null;

    /**
     * 元素总数
     */
    private int size = 500;

    /**
     * 记录总数
     */
    private int count = 0;

    public KHashMap(){
        this.entries = new Object[this.size];
    }

    public KHashMap(int size){
        this.size = size;
        this.entries = new Object[this.size];
    }

    /**
     * 获得下标
     * @param key
     * @return
     */
    private int getIndex(Object key){
        int h = 0;
        int code = 0;
        if(key != null) {
            h = key.hashCode() & 0x0FFFFFFF;
            code = h ^ (h >>> 16);
        }
        return code % size;
    }

    /**
     * 设置键
     * @param key
     * @param value
     */
    public synchronized void put(K key, V value){
        if(key == null){
            throw new NullPointerException("key is null.");
        }

        // 获得下标
        int index = getIndex(key);
        Entry<K, V> o = (Entry<K, V>) entries[index];

        // 如果下标存在元素:
        if(o != null){
            // 插入元素到链表
            insert(o,  key, value);
        } else{
            // 直接创建新元素
            entries[index] = new Entry<K, V>(key,  value, null);
            count++;
        }
    }

    /**
     * 获取值
     * @param key
     * @return
     */
    public synchronized V get(K key){
        if(key == null){
            throw new NullPointerException("key is null.");
        }

        // 获取下标
        int k = getIndex(key);

        // 去对应下标查询值:
        Entry<K, V> o = (Entry<K, V>)entries[k];

        // 如果存在元素:
        if(o != null){
            // 链表存在,查询链表返回。
            return find(o, key);
        }
        return null;
    }

    /**
     * 移除节点
     * @param key
     * @return
     */
    public synchronized boolean remove(K key){
        // 找到位置清除
        if(key == null){
            throw new NullPointerException("key is null.");
        }

        // 获得下标
        int index = getIndex(key);
        Entry<K, V> o = (Entry<K, V>)entries[index];

        // 如果存在元素
        if(o != null){
            // 找到位置,清除元素链表
            Entry<K, V> p = o;
            Entry<K, V> pre = null;

            while(p != null){
                if(p.getKey().equals(key)){
                    break;
                }
                pre = p;
                p = p.getNext();
            }

            // 如果不为空,代表找到元素了
            if(p != null){
                if(pre != null){
                    pre.setNext(p.getNext());
                } else {
                    // 说明是第一个节点
                    entries[index] = p.getNext();
                }
                count--;
                return true;
            } else {
                return false;
            }
        }

        return false;
    }


    /**
     *  从链表中设置元素
     * @param p
     * @param key
     * @param value
     */
    private synchronized void insert(Entry<K, V> p, K key, V value){
        Entry<K, V> pre = null;

        while(p != null){
            // 键名相等就设置
            if(p.getKey() != null && p.getKey().equals(key)){
                p.setValue(value);
                break;
            }
            // 记录上一个元素
            pre = p;
            p = p.getNext();
        }

        // 如果为空,代表是全部查了
        if(p == null && pre != null){
            // 添加到末尾
            pre.setNext(new Entry<K, V>(key,  value, null));
            count++;
        }
    }

    /**
     * 从链表中查询元素
     * @param p 链表
     * @param key 键名
     * @return
     */
    private V find(Entry<K, V> p, Object key){
        V v = null;
        while(p != null){
            if(p.getKey() != null && p.getKey().equals(key)){
                v = p.getValue();
                break;
            }
            p = p.getNext();
        }
        return v;
    }

    /**
     * 获取元素个数
     * @return
     */
    public synchronized int size(){
        return this.count;
    }

    /**
     * 获得键的集合
     * @return
     */
    public synchronized Object[] keys(){
        Object[] result = new Object[count];
        int index = 0;
        for(int k = 0; k < size; k++){
            Entry<K, V> temp = (Entry<K, V>) entries[k];
            while(temp != null){
                if(index < result.length) {
                    result[index] = temp.getKey();
                    temp = temp.getNext();
                    index++;
                }
            }
        }
        return result;
    }

    /**
     * 获取值的数组
     * @return
     */
    public synchronized Object[] values(){
        Object[] result = new Object[count];
        int index = 0;
        for(int k = 0; k < size; k++){
            Entry<K, V> temp = (Entry<K, V>) entries[k];
            while(temp != null){
                if(index < result.length){
                    result[index] = temp.getValue();
                    temp = temp.getNext();
                    index++;
                }
            }
        }
        return result;
    }

    /**
     * 清空元素
     */
    public synchronized void clear(){
        // 重新指向新的对象数组
        this.entries = new Object[this.size];
    }
}

三、测试代码

1、代码

java 复制代码
/**
 * @author
 * @version 1.0.0
 * <p>
 * date: 2026/4/22
 **/
public class Test {

    public static void main(String[] args) {

        KHashMap<String, String> map = new KHashMap<String, String>();
        map.put("nnn1", "小明");
        map.put("nnn2", "小红");
        map.put("nnn3", "小花");

        System.out.println("nnn1:" + map.get("nnn1"));
        System.out.println("nnn2:" + map.get("nnn2"));
        System.out.println("nnn3:" + map.get("nnn3"));
        System.out.println("个数:" + map.size());

        System.out.println("键的集合:");
        Object[] keys = map.keys();
        for (int i = 0; i < keys.length; i++) {
            System.out.println(keys[i]);
        }
        System.out.println("-----------");

        System.out.println("值的集合:");
        Object[] values = map.values();
        for (int i = 0; i < values.length; i++) {
            System.out.println(values[i]);
        }
    }
}

2、执行结果

四、总结

1、基本满足实现要求。

2、最复杂的是计算下标、操作链表的新增节点、删除节点、查找节点。

相关推荐
后端AI实验室2 小时前
我带的那个实习生,比我更依赖AI——但他的问题和我完全不同
java·ai
Ulyanov2 小时前
《玩转QT Designer Studio:从设计到实战》 QT Designer Studio状态机深度应用:智能待办事项管理系统
开发语言·python·qt·gui·雷达电子对抗系统仿真
MinterFusion2 小时前
如何使用Qt5在窗口中显示矩形(v0.1.3)(上)
开发语言·qt·编程·明德融创·窗口中绘制矩形
y小花2 小时前
安卓StorageManagerService
android·java
码王吴彦祖2 小时前
AI 逆向分析国航 AirChina FECU 参数来源并实现离线生成
android·java·javascript
LJianK12 小时前
进程、线程、多线程、异步
java·开发语言·jvm
ch.ju2 小时前
Java程序设计(第3版)第二章——循环结构1
java
大黄烽2 小时前
IDEA中集成AI 工具CodeBuddy和Trae区别和选型
java·人工智能·intellij-idea
JMchen1232 小时前
第 1 篇|Kotlin 基础入门 —— 变量、函数与空安全
开发语言·kotlin·android 入门·kotlin 空安全·android 零基础