从手写HashMap说起,解析HashMap原理(未完待续)

最近面试时,经常被问到hashmap相关的问题。作为一名java程序员,有必要了解hashmap的底层原理。网上相关资料很多,我个人认为还是要从源码入手。直接看源码不容易理解,那么我们可以尝试自己写一个hashmap然后再逐步分析并参考源码来思考。

需求分析

首先从需求角度来想,明确什么是hashmap,为什么要用hashmap?
简单说,hashmap就是个存储键值对的集合,那么手写hashmap需要满足如下几点需求:
(1)可以存放多个键值对数据
(2)具有put和get方法,用于存取数据
(3)key值不可重复,当存入数据的key值存在时,覆盖原value
(4)既然叫hashmap,就要利用hash的特性提高效率,否则就是一种map而已称不上hashmap

编码思路

简单总结如上4点吧,现在开始写:
(1)创建一个名叫hashmap的类,类中写两个方法分别是put和get
(2)考虑到要写的是个集合,首先想到能利用的就是数组了,于是给hashmap类增加一个数组类型的成员变量table,以及整型的初始容量CAPACITY
(3)然而存放的数据是键值对,我们就需要创造这样一个“键值对”形式的对象。暂时取名叫Entry。

    class Entry<K, V> {
        public K key;
        public V value;
        public Entry<K, V> next;

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

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

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }
    }

这个Entry对象起码需要有两个成员变量,分别是key和value。然而考虑到hash冲突的问题,我们将Entry对象设计成链表的形式,实现在数组同一个index上存放多个Entry对象。当发生冲突时,将新的Entry对象的next变量指向前一个Entry对象(也就是插入前的table[index]),然后将table[index]上放入新的Entry对象(table[index]=newEntry)
(4)进一步完善put和get方法得到最终的hashmap类
需要完善如下几点问题:
1、完成从hash值到数组index下标的映射,这里采用取余的方式。
2、put方法中,当映射的index下标一致时,采用链表形式在index处存放Entry对象
3、get方法中,当映射的index下标一致时,遍历链表获取key值对应的value
4、当key值相同时,覆盖原有value

最终代码

public class MyHashMap<K, V> {

    private Entry<K, V>[] table;
    private static final Integer CAPACITY = 8;
    private int size;

    public void put(K k, V v) {
        if (table == null) {
            inflate();
        }
        //save entry
        int hashCode = hashCodeMethod(k);
        int index = getIndexOfHashCode(hashCode);

        for (Entry<K, V> entry = table[index]; entry != null; entry = entry.next) {
            if (entry.key.equals(k)) {
                entry.value = v;
                return;
            }
        }
        addEntry(k, v, index);

    }

    public V get(K k) {
        int hashCode = hashCodeMethod(k);
        int index = getIndexOfHashCode(hashCode);

        for (Entry<K, V> entry = table[index]; entry != null; entry = entry.next) {
            if (entry.key.equals(k)) {
                return entry.value;
            }
        }
        return null;
    }

    private void addEntry(K k, V v, int index) {
        Entry<K, V> newEntry = new Entry<>(k, v, table[index]);
        table[index] = newEntry;
        size++;
    }

    private int getIndexOfHashCode(int hashCode) {
        return hashCode % table.length;
    }

    private int hashCodeMethod(K k) {
        return k.hashCode();
    }

    private void inflate() {
        table = new Entry[CAPACITY];
    }

    class Entry<K, V> {
        public K key;
        public V value;
        public Entry<K, V> next;

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

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

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }
    }

    public static void main(String[] args) {
        MyHashMap<String,String> myHashMap = new MyHashMap<>();
        myHashMap.put("1","v");
        myHashMap.put("2","2v");
        myHashMap.put("2","3v");
        System.out.println(myHashMap.get("2"));
    }
}

深入思考

显然,这样的hashmap还存在很多问题,这些问题也正是我们要思考的:
1、数组的容量设置为了8,如果数据量较大时该怎么办?如何扩容?
2、完成从hash值到数组index下标的映射,这里采用取余的方式。
然而取余这种操作比较耗时,能否进一步提高效率?
3、get方法中,当映射的index下标一致时,遍历链表获取key值对应的value。然而遍历这种操作比较耗时,能否进一步提高效率?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 摘要 HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型。随着JDK(Java Deve...
    周二倩你一生阅读 1,403评论 0 5
  • 一、HashMap概述 HashMap基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许使用nul...
    小陈阿飞阅读 714评论 0 2
  • 本文转自 https://zhuanlan.zhihu.com/p/21673805 美团点评技术团队· 3 个月...
    抓兔子的猫阅读 1,190评论 0 1
  • 泰国气候雨水多,大风经常刮倒树, 堵车也是常有的事,大雨天别出门, 省得路上找麻烦,幼儿园去不了, 外面还在下大雨...
    荣兰_a5f9阅读 54评论 0 0
  • 好久不主动联系人,也许久许久没人联系自己,一种独自在世界的感觉。偶尔感到孤独和无趣,总感觉少了人分享自己的乐趣。持...
    江醉心阅读 110评论 0 0

友情链接更多精彩内容