HashMap(4)--动手实现HashMap

7 篇文章 0 订阅
1 篇文章 0 订阅

本来这篇博客想写HashMap的遍历机制的,看了好久的源码表示没有看懂。。。吼吼,有好的博客可以推荐几篇。看到了一篇感觉还不错的博客,但是没有看懂。

1.先定义myMap接口

public interface MyMap<K, V> {
    V get(K key);

    V put(K key, V value);

    int getSize();

    interface Entry<K, V> {
        K getKey();

        V getValue();

        void setValue(V value);
    }


}

2.对Map接口进行实现。

import java.util.Arrays;


public class MyHashMap<K, V> implements MyMap<K, V> {
    //默认的初始容量的大小
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
    // 默认的负载因子的大小
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;
    //键值对的数量
    transient int size;
    //定义一个阀值 创建数组的长度*负载因子的大小
    int threshold;
    //初始化负载因子的大小
    final float loadFactor;

    //定义一个 Entry 数组
    transient Node<K, V>[] table;
    //记录数组的长度
    int initialCapacity;

    //构造函数
    public MyHashMap() {
         this.loadFactor = DEFAULT_LOAD_FACTOR;
         this.initialCapacity = DEFAULT_INITIAL_CAPACITY;
         this.threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    }

    public MyHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public MyHashMap(int initialCapacity, float loadFactor) {
        this.loadFactor = initialCapacity;
        //initialCapacity 为通过各种计算
        // 获取大于 initialCapacity 那个2^n 倍的那个数
        int newInitialCapacity = getNewInitialCapacity(initialCapacity);
        this.initialCapacity = newInitialCapacity;
        this.threshold = (int) (newInitialCapacity * loadFactor);
    }

    private int getNewInitialCapacity(int initialCapacity) {
        int n = initialCapacity - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return n > MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : n + 1;
    }

    /**
     * 计算 key 的 Hash 值
     *
     * @param key
     * @return
     */
    public int hash(K key) {
        return key.hashCode();
    }

    /**
     * 通过Hash值计算 key 所在的坐标
     *
     * @param hash
     * @return
     */
    public int indexFor(int hash) {
        return hash % (table.length - 1);
    }

    /**
     * 获取键值对
     *
     * @param key
     * @return
     */
    @Override
    public V get(K key) {
        // 计算在数组中的位置
        if (table != null && table.length > 0 && key != null) {
            int index = indexFor(hash(key));
            Node<K, V>[] tab;
            Node<K, V> node;
            if ((tab = table) != null && tab.length > 0) {
                node = tab[index];
                while (node != null) {
                    if (key != null && key.equals(node.key)) {
                        return node.value;
                    }
                    node = node.next;
                }
            }
        }
        return null;
    }

    /**
     * 储存键值对
     *
     * @param key
     * @param value
     * @return
     */
    @Override
    public V put(K key, V value) {
        if (table == null) {
            this.table = resize();
        }

        int index = indexFor(hash(key));
        if (table[index] == null) {
            Node<K, V> node = new Node<K, V>(key, value, null);
            this.table[index] = node;
        } else {
            Node<K, V> node = table[index];
            Node<K, V> next = node;
            for (; next != null; ) {
                node = next;
                if (key.equals(node.key)) {
                    V oldValue = node.value;
                    node.value = value;
                    return oldValue;
                }
                next = node.next;
            }
            Node<K, V> newNode = new Node<K, V>(key, value, null);
            node.next = newNode;

        }
        if (++size > this.threshold) {
            resize();
        }
        return null;
    }

    @Override
    public int getSize() {
        return this.size;
    }

    /**
     * 进行扩容
     *
     * @return
     */
    private Node<K, V>[] resize() {
        if (table == null) {
            return new Node[this.initialCapacity];
        }
        //重新Hash值
        int n = table.length;
        Node[] newTable = new Node[n * 2];
        for (int i = 0; i < n; i++) {
            if (table[i] != null && n > 0 && table[i].next == null) {
                int index = indexFor(hash(table[i].key));
                newTable[index] = table[i];
            } else if (table[i] != null && n > 0 && table[i].next != null) {
                Node<K, V> node = table[i];
                Node<K, V> loHead = null, loTail = null;
                Node<K, V> hiHead = null, hiTail = null;
                Node<K, V> next;
                do {
                    next = node.next;
                    int hash = hash(node.key);
                    if ((hash & n) == 0) {
                        if (loHead == null) {
                            loHead = node;
                        } else {
                            loTail.next = node;
                        }
                        loTail = node;

                    } else {
                        if (hiHead == null) {
                            hiHead = node;
                        } else {
                            hiTail.next = node;
                        }

                        hiTail = node;
                    }
                } while ((node = node.next) != null);

                if (loHead != null) {
                    hiTail.next = null;
                    newTable[i] = loHead;
                }

                if (hiHead != null) {
                    hiHead.next = null;
                    newTable[i + n] = hiHead;
                }
            }
        }
        //执行使用旧的 table 通过重新计算坐标进行重新赋值
        //省略n多步骤
        table = newTable;
        return newTable;
    }

    static class Node<K, V> implements MyMap.Entry<K, V> {
        final K key;
        V value;
        Node next;

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


        @Override
        public K getKey() {
            return this.key;
        }

        @Override
        public V getValue() {
            return this.value;
        }

        @Override
        public void setValue(V value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "key=" + key +
                    ", value=" + value +
                    ", next=" + next +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "MyHashMap{" +
                "table=" + Arrays.toString(table) +
                '}';
    }
}

3.扩容机制测试:


public class Test {

    public static void main(String[] args) {
        MyMap<String, String> map = new MyHashMap(11);
        map.put("1", "1");
        map.put("2", "2");
        map.put("3", "3");
        map.put("4", "4");
        map.put("5", "5");
        map.put("6", "6");
        map.put("7", "7");
        map.put("17", "1");
        map.put("a", "1");
        map.put("c", "1");
        map.put("d", "1");
        map.put("e", "1");
        map.put("f", "1");
        System.out.println(map);
    }
}

4.存取测试

public class Test1 {
    public static void main(String[] args) {
        MyMap<String, String> map = new MyHashMap(11);
        map.put("1", "1");
        map.put("2", "2");
        map.put("3", "3");
        map.put("4", "4");
        map.put("5", "5");
        String put = map.put("5", "6");
        System.out.println(put);
        System.out.println(map.get("5"));
        System.out.println(map.getSize());
    }
}

发现问题请留言


帅照展示时间:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值