zoukankan      html  css  js  c++  java
  • 简易HashMap实现

    为了更好的理解HashMap线程不安全的根源,这里提供了HashMap的简易实现:

    package map.test;
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * Author:yepei@meituan.com
     * Date:2017/7/5
     * Time:15:45
     * ------------------------------------
     * Desc:
     */
    public class HashMp {
        private transient Node[] entries;//数组
        private transient float loadFactor;
        private transient int size;
    
        public static void main(String[] args) {
            HashMp map = new HashMp(2, 0.75f);
            map.put(3, "A");
            System.out.println(map);
            map.put(5, "B");
            map.put(7, "C");
            map.put(11, "D");
            map.put(9, "E");
            map.put(12, "F");
            map.put(17, "G");
            map.put(22, "H");
            map.put(24, "I");
            map.put(25, "I");
            System.out.println(map);
    
            String s1 = map.get(22);
            String s2 = map.get(25);
            String s3 = map.get(0);
        }
    
        public HashMp(int capacity, float loadFactor) {
            this.entries = new Node[capacity];
            this.loadFactor = loadFactor;
        }
    
        public HashMp() {
            this(16, 0.75f);
        }
    
        public String put(int key, String value) {
            Node n = new Node(key, value);
            //算Hash值,为简单起见,hash值
            int i = n.getIndex(entries.length);
            Integer thisKey = key;
            //查找是否有重复: hashCode相等,且equals方法相等的
            for (Node old = entries[i]; old != null; old = old.next) {
                Integer oldKey;
                //hash相同,且equals返回true,证明有重复值插入,直接替换掉旧值
                if (old.getHash() == n.getHash() && ((oldKey = old.key) == key || thisKey.equals(oldKey))) {
                    String oldValue = old.value;
                    old.value = value;//替换成新值
                    return oldValue;//返回旧值
                }
            }
            //该key不存在,需要增加一个结点
            addEntry(n);
            return null;
        }
    
        public String get(int key) {
            int idx = new Node(key, null).getIndex(entries.length);
            Integer thisKey = key;
            //查找是否有重复: hashCode相等,且equals方法相等的
            for (Node old = entries[idx]; old != null; old = old.next) {
                Integer oldKey = old.key;
                if (thisKey == oldKey || thisKey.equals(oldKey)) {
                    return old.value;
                }
            }
            return null;
        }
    
        private void addEntry(Node n) {
            int oldLen = entries.length;
            int targetIdx = n.getIndex(oldLen);
            n.next = entries[targetIdx];
            entries[targetIdx] = n;//插入到链首
            if (size++ >= oldLen * loadFactor) {
                resize(2 * oldLen);
            }
        }
    
        private void resize(int newCapacity) {
            Node[] old = entries;
            Node[] newMap = new Node[newCapacity];
            for (int j = 0; j < old.length; j++) {
                Node e = old[j];
                if (e == null) {
                    continue;
                }
                old[j] = null;//老表中的元素置为Null
                
                //注意:该过程会将同一个bucket中的元素逆置,因为总是将元素插在了新表的头部。
                //但不是就地逆置,因为将元素逐个copy到了新的链表中
                do {
                    Node next = e.next;//暂存尾链表(去掉head的链表)
                    int i = e.getIndex(newCapacity);//得到将在新表中存储的位置
                    e.next = newMap[i];//切断指针,重新指向新表的表头(可能为null)
                    newMap[i] = e;//将e插入到新链表头部
                    e = next;//重新将e赋值为尾链表的头,对尾链表继续“切断指针,插入新表头”
                } while (e != null);
            }
            entries = newMap;
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("[");
            int i = 0;
            for (Node n : entries) {
                sb.append(i++).append("{").append(n).append("}, ");
            }
            return StringUtils.removeEnd(sb.toString(), ", ") + "]";
        }
    
        static class Node {
            int key;
            String value;
            Node next;
    
            Node(int key, String value) {
                this.key = key;
                this.value = value;
            }
    
            int getIndex(int tableLength) {
                return getHash() % tableLength;
            }
    
            //为方便起见,hash值直接取该对象的key
            int getHash() {
                return key;
            }
    
            @Override
            public String toString() {
                return "(" + key + "," + value + ")——>" + next;
            }
        }
    }
    

      

    参考

    HashMap源码解读:http://www.xiaomager.com/category/program/java/hashmap

    Hashcode生成原理:http://www.cnblogs.com/godtrue/p/6395098.html

    HashMap存在的三大并发问题:https://my.oschina.net/xianggao/blog/393990

  • 相关阅读:
    HTTP协议
    网络编程笔记
    基于udp协议实现QQ:可以并发一对多
    基于udp协议通信:实现了并发
    基于tcp协议通信,运用socketserver模块实现并发
    @PathVariable 与@RequestParam
    IDEA 中的一些概念变化
    Bubble Cup 11
    ACM超时问题
    D
  • 原文地址:https://www.cnblogs.com/yepei/p/7122527.html
Copyright © 2011-2022 走看看