美文网首页JDK源码系列Java 杂谈
JDK 学习之(一)HashMap 的实现

JDK 学习之(一)HashMap 的实现

作者: 罗曼蒂克 | 来源:发表于2017-12-15 23:19 被阅读22次

    已经有很多如何深入学习认识HashMap 的文章了,我就不重复了.
    我就自己实现了简单的 HashMap,仅供学习了解 HashMap 核心思想之用

    1. 底层采用数组+链表的形式来存储 键值对
    2. 键值对使用 Entity 对象存储,数组存储 LinkedList
    3. 如果 hash 值重复,则在该 index 对象(LinkedList)头部插入新的元素

    以上可以勾勒出如下图所示的一幅结构:


    屏幕快照 2017-12-15 下午10.36.37.png

    下面我们来看一下具体的实现
    如下代码是内部类,用来存放键值对,两个 Object 对象,没什么好说的

        /**
         * 内部类用来存放键值对
         */
        class MyEntry {
            private Object key;
            private Object value;
            private MyEntry(Object key, Object value) {
                this.key = key;
                this.value = value;
            }
            //省略 get,set 方法
        }
    

    如下是用到的几个字段

        private static int default_length = 999;//不涉及到扩容,这里写死这个容量
        private int size = 0;//初始容器大小
        private Object[] arr = new Object[default_length];//声明一个数组用来存放键值对
    

    提供以下API 操作
    boolean put(Object key,Object value)
    Object get(Object key)
    int size()
    内部还有两个私有方法
    boolean containsKey(Object key, int index)查看指定位置是否包含指定 key
    int hash(Object key)计算 key 的 hash 值,即该 key 在数组中的位置

    具体详细代码如下

    
        private static int default_length = 999;
        private int size = 0;
    
        private Object[] arr = new Object[default_length];
    
        /**
         * 放入键值对
         * @param key
         * @param value
         */
        public void put(Object key, Object value) {
            int index = hash(key);
            if (arr[index] == null) {
                // 如果当前槽位是空的,直接放进去就可以了
                List linkedList = new LinkedList();
                linkedList.add(new MyEntry(key, value));
                arr[index] = linkedList;
            } else {
                //如果不为空,检查当前 key 是否已存在
                //如果已经存在,替换 value, 否则在链表头部插入新的元素
                if (containsKey(key, index)) {
                    LinkedList linkedList = (LinkedList) arr[index];
                    for (Object o : linkedList) {
                        MyEntry entry = (MyEntry) o;
                        if (entry.getKey().equals(key)) {
                            entry.setValue(value);
                        }
                    }
                    return;
                } else {
                    //链表头部插入元素
                    ((LinkedList) arr[index]).add(0, new MyEntry(key, value));
                }
            }
            size++;
        }
    
    
        /**
         * hashMap 中指定位置是否包含指定key
         * @param key
         * @param index
         * @return
         */
        private boolean containsKey(Object key, int index) {
            Object o = arr[index];
            if (o == null) {
                return false;
            }
            LinkedList linkedList = (LinkedList) o;
            for (Object o1 : linkedList) {
                if (o1 == null && key == null) {
                    return true;
                }
                MyEntry entry = (MyEntry) o1;
                if (entry.getKey().equals(key)) {
                    return true;
                }
            }
            return false;
        }
    
        /**
         * 根据 key 获取 value
         * 如果 key==null,特殊处理,放在了第一个位置
         * 获得 key 的 hash 值,就确定了在 数组中的位置.
         * 遍历该链表
         * @param key
         * @return
         */
        public Object get(Object key) {
            if (key == null) {
                return ((MyEntry) ((LinkedList) arr[0]).getFirst()).getValue();
            }
            int index = hash(key);
            Object o = arr[index];
            if (o == null) {
                return null;
            }
            LinkedList linkedList = (LinkedList) o;
            for (Object o1 : linkedList) {
                if (o1 == null) {
                    return null;
                }
                MyEntry entry = (MyEntry) o1;
                if (entry.getKey().equals(key)) {
                    return entry.getValue();
                }
            }
            return null;
        }
    
        /**
         * 给定一个对象计算其 hash 值
         *
         * @param key
         * @return
         */
        private int hash(Object key) {
            if (key == null) {
                return 0;
            }
            return key.hashCode() & default_length;
        }
    

    注意:真实的 HashMap 还有个字段阈值,用来控制 hashMap 的负载默认75%,即:容量达到数组的75%时进行扩容操作,举个例子:容量16,当放入第13个元素的时候进行扩容操作.
    代码在这里 GitHub

    多多评论,多多指教

    相关文章

      网友评论

        本文标题:JDK 学习之(一)HashMap 的实现

        本文链接:https://www.haomeiwen.com/subject/kcwdwxtx.html