自定义实现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、最复杂的是计算下标、操作链表的新增节点、删除节点、查找节点。

相关推荐
JAVA学习通8 小时前
北京明光云振铎数据科技Java面经
java·开发语言·科技
贫民窟的勇敢爷们14 小时前
SpringBoot整合AOP切面编程实战,实现日志统一记录+接口权限校验
java·spring boot·spring
jerryinwuhan14 小时前
基于各城市站点流量的复合功能比较
开发语言·php
AC赳赳老秦15 小时前
供应链专员提效:OpenClaw自动跟踪物流信息、更新库存数据,异常自动提醒
java·大数据·服务器·数据库·人工智能·自动化·openclaw
迈巴赫车主15 小时前
Java基础:list、set、map一遍过
java·开发语言
灵犀学长15 小时前
基于 Spring ThreadPoolTaskScheduler + CronTrigger 实现的动态定时任务调度系统
java·数据库·spring
南 阳16 小时前
Python从入门到精通day66
开发语言·python
好家伙VCC17 小时前
【无标题】
java
十八旬17 小时前
快速安装ClaudeCode完整指南
开发语言·windows·python·claude
前进的李工17 小时前
EXPLAIN输出格式全解析:JSON、TREE与可视化
开发语言·数据库·mysql·性能优化·explain