根据数组+链表的原理,自己实现一个简易版的HashMap

根据数组+链表的原理,自己实现一个简易版的HashMap

前言

昨天被人问到了HashMap底层实现方式,然而自己却只知道用hashCode()方法实现。虽然有看过HashMap源码,但自己却一直没搞懂具体实现方式。于是,从朋友那里借来一本书,专门研究了一下Map,才发现原来底层实现就是“数组 + 链表”的形式(顿时无语,当时自己居然没看出来!!)。

接上两篇“数组 + 链表”,本次还是尝试自己根据其原理来实现一个简易版的HashMap。

HashMap简介

  • HashMap底层实现原理
    • ‘数组’里面放’链表’,‘链表’里面放的’Entry(key,value)’
    • 【注:Java8中,链表长度达到8,并且数组长度达到64,链表将切换为红黑树结构】
  • 大致模型
    • 数组{链表1, 链表2, 链表3}
    • 链表1(Entry1<—>Entry2<—>Entry3) 或红黑树
    • Entry1(key, value)
  • 查找value的方式
    1. 先根据key的hashCode对容器size取余数,找到数组里面的链表对象。实际是 (length -1) & hashcode),length为2的n次方时,效果等同,速度更快。
    2. 再遍历链表,根据key找到value(此时是用的key.equals()进行比较)

代码如下

import java.util.LinkedList;

/**
 * 自己实现一个简易版的HashMap
 *
 * @author ALion
 * @version 2017/11/4 16:03
 */
public class MyHashMap<K, V> {

    private LinkedList[] arr = new LinkedList[1024];

    private int size;

    public int size() {
        return size;
    }

    /**
     * 存入一个key-value对
     */
    public void put(K key, V value) {
        MyEntry<K, V> entry = new MyEntry<>(key, value);
        int num = (key.hashCode() & 0x7FFFFFFF) % arr.length;//也可以Math.abs(key.hashCode() % arr.length)
        // HashMap源码中此处num为 (length - 1) & hash,当length为2的n次方时,和 hash % (length - 1)等价
        // HashMap中数组的length总是为2的n次方,由扩容算法决定
        // get方法同理
        if (arr[num] == null) {
            LinkedList list = new LinkedList();
            list.add(entry);
            arr[num] = list;
        } else {
        	// 此处使用链表,而Java8中还加入了红黑树
            LinkedList list = arr[num];
            for (Object obj : list) {
                MyEntry e = (MyEntry) obj;
                if (e.key.equals(key)) {
                    e.value = value; //如果key相同,就覆盖
                    return;
                }
            }
            arr[num].add(entry);
        }
        size++;
    }

    /**
     * 根据key,获取value
     */
    public V get(K key) {
        int num = (key.hashCode() & 0x7FFFFFFF) % arr.length;//也可以Math.abs(key.hashCode() % arr.length)
        if (arr[num] != null) {
            LinkedList list = arr[num];
            for (Object obj : list) {
                MyEntry<K, V> entry = (MyEntry<K, V>) obj;
                if (entry.key.equals(key)) {
                    return entry.value;
                }
            }
        }
        return null;
    }

    /**
     * key-value的封装类
     */
    static class MyEntry<K, V> {

        K key;
        V value;

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

测试一下

/**
 * Main
 *
 * @author ALion
 * @version 2017/11/4 16:02
 */
public class Main {

    public static void main(String[] args) {
        MyHashMap<String, String> map = new MyHashMap<>();
        map.put("zhangsan", "chongqing");
        map.put("lisi", "beijing");
        map.put("wangwu", "shanghai");
        System.out.println(map.get("lisi"));

        MyHashMap<String, Integer> map2 = new MyHashMap<>();
        map2.put("zhangsan", 18);
        map2.put("lisi", 26);
        map2.put("lisi", 28);
        System.out.println(map2.get("lisi"));

        System.out.println(map2.size());
    }

}

其他

  • 关于元素在数组中的位置的计算示例
    int length = 32;
    // i 即 hashcode
    for (int i = 1; i < 100; i++) {
        System.out.println("-------效果相同-------");
        System.out.println(i + " % " + length + " = " + (i % length));
        System.out.println(length - 1 + " & " + i + " = " + ((length - 1) & i));
    }
    
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值