深入理解HashMap:从Java实现到自定义实现

引言

HashMap作为Java集合框架中最重要且最常用的数据结构之一,其高效的键值对存储和快速查找特性使其成为开发者的首选。本文将深入剖析Java原生HashMap的实现原理,并介绍我实现的自定义版本MyHashMap,最后对比两者的设计差异与性能特点。

Java原生HashMap解析

基本结构

Java的HashMap是基于哈希表的Map实现,主要特点包括:

  1. 数组+链表+红黑树:JDK8后引入红黑树优化极端情况

  2. 动态扩容:默认负载因子0.75时扩容

  3. 快速查找:平均时间复杂度O(1)

核心实现机制

// JDK中的关键字段
transient Node<K,V>[] table; // 哈希桶数组
static final int DEFAULT_INITIAL_CAPACITY = 16; // 默认初始容量
static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认负载因子

// 节点定义
static class Node<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
}

哈希计算

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

扩容机制

final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int newCap = oldCap << 1; // 双倍扩容
    // ...迁移数据...
}

自定义MyHashMap实现

package com.zsy;

/**
 * 自定义HashMap实现,基于数组+链表的结构
 *
 * <p>本实现提供类似Java HashMap的核心功能,包括:</p>
 * <ul>
 *   <li>基于哈希表的键值对存储</li>
 *   <li>使用链表解决哈希冲突</li>
 *   <li>自动扩容机制</li>
 *   <li>基本CRUD操作</li>
 * </ul>
 *
 * <p><b>特性说明:</b></p>
 * <ul>
 *   <li>初始容量:16</li>
 *   <li>负载因子:0.75</li>
 *   <li>扩容策略:容量翻倍</li>
 *   <li>哈希计算:key.hashCode() & (capacity-1)</li>
 *   <li><b>非线程安全</b> - 多线程环境下需要外部同步</li>
 * </ul>
 *
 * @param <K> 键类型
 * @param <V> 值类型
 * @author zsy
 */
public class MyHashMap<K, V> {

    /**
     * 默认初始容量 - 必须是2的幂
     */
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    /**
     * 默认负载因子
     */
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * 哈希表数组
     */
    private Node<K, V>[] table;

    /**
     * map中键值对的数量
     */
    private int size;

    /**
     * 构造一个具有默认初始容量(16)和默认负载因子(0.75)的空HashMap
     */
    public MyHashMap() {
        this.table = new Node[DEFAULT_INITIAL_CAPACITY];
    }

    /**
     * 将指定的键值对存入map
     *
     * @param key 键
     * @param value 值
     * @return 与key关联的旧值,如果没有则返回null
     */
    public V put(K key, V value) {
        int index = hash(key);
        Node<K, V> head = table[index];

        // 查找是否已存在相同key
        while (head != null) {
            if (head.key.equals(key)) {
                V oldValue = head.value;
                head.value = value;
                return oldValue;
            }
            head = head.next;
        }

        // 添加新节点
        Node<K, V> newNode = new Node<>(key, value);
        newNode.next = table[index];
        table[index] = newNode;
        size++;

        // 检查是否需要扩容
        resizeIfNeeded();
        return null;
    }

    /**
     * 获取指定键对应的值
     *
     * @param key 键
     * @return 与key关联的值,如果没有则返回null
     */
    public V get(K key) {
        int index = hash(key);
        Node<K, V> node = table[index];
        while (node != null) {
            if (node.key.equals(key)) {
                return node.value;
            }
            node = node.next;
        }
        return null;
    }

    /**
     * 移除指定键对应的键值对
     *
     * @param key 键
     * @return 被移除的值,如果没有则返回null
     */
    public V remove(K key) {
        int index = hash(key);
        Node<K, V> node = table[index];
        Node<K, V> prev = null;

        while (node != null) {
            if (node.key.equals(key)) {
                if (prev == null) {
                    table[index] = node.next;
                } else {
                    prev.next = node.next;
                }
                size--;
                return node.value;
            }
            prev = node;
            node = node.next;
        }
        return null;
    }

    /**
     * 返回map中键值对的数量
     *
     * @return map中键值对的数量
     */
    public int size() {
        return size;
    }

    /**
     * 计算key的哈希索引
     */
    private int hash(Object key) {
        return key.hashCode() & (table.length - 1);
    }

    /**
     * 检查并执行扩容操作
     */
    private void resizeIfNeeded() {
        if (size < table.length * DEFAULT_LOAD_FACTOR) {
            return;
        }

        int newCapacity = table.length << 1;
        Node<K, V>[] newTable = new Node[newCapacity];

        // 重新哈希所有节点
        for (Node<K, V> head : table) {
            while (head != null) {
                Node<K, V> next = head.next;
                int newIndex = head.key.hashCode() & (newCapacity - 1);
                head.next = newTable[newIndex];
                newTable[newIndex] = head;
                head = next;
            }
        }

        table = newTable;
    }

    /**
     * HashMap节点类
     */
    static class Node<K, V> {
        final K key;
        V value;
        Node<K, V> next;

        Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值