Bootstrap

实现粗糙版的HashMap

Hashmap的实现原理:

import java.util.HashMap;

public class Node<K,V> {
    private K  key;
    private Node<K,V> next=null;
    private V obj;

    public K getKey() {
        return key;
    }

    public void setKey(K key) {
        this.key = key;
    }

    public void setNext(Node<K,V> next) {
        this.next = next;
    }

    public Node<K,V> getNext() {
        return next;
    }

    Node(K key,V obj) {
        this.key=key;
        this.obj = obj;
    }

    public void setObj(V obj) {
        this.obj = obj;
    }

    public V getObj() {
        return obj;
    }
}}

首先是链表的实现原理
1.节点node里存了k,v就是key和value两个值。
2.getnext用来获取下一个节点。
3.setnext用来设置下一个节点。

接口

public abstract class MyHashMap<K, V> {
    abstract int size();

    abstract boolean isEmpty();

    abstract boolean containsKey(K key);

    abstract V get(K key);

    abstract V put(K key, V value);

    abstract V remove(K key);

    abstract void clear();
}

实现类

public class HashMap01<K, V> extends MyHashMap<K, V> {
    private int size = 0;
    private int cap = 16;
    Node<K, V>[] array = new Node[cap];
    private final double anInt = 0.75;


    @Override
    int size() {
        return size;
    }

    @Override
    boolean isEmpty() {
        return size == 0;
    }

    @Override
    boolean containsKey(Object key) {
        Node n;
        int i = key.hashCode() % cap;
        if (array[i] != null) {
            n = array[i];
            while (null != n) {
                if (!key.equals(n.getKey())) {
                    n = n.getNext();
                } else return true;
            }

        }


        return false;
    }

    @Override
    V get(K key) {
        Node n;
        int i = key.hashCode() % cap;
        if (array[i] != null) {
            n = array[i];
            while (null != n) {
                if (!key.equals(n.getKey())) {
                    n = n.getNext();
                } else return (V) n.getObj();
            }

        }

        return null;
    }
    @Override
    V put(K key, V value) {
        judgmentCapacity();
        Node n;
        int nums = key.hashCode() % cap;
        if (array[nums] == null) {
            array[nums] = new Node<>(key, value);
            size++;
            return null;
        }
        n = array[nums];
        if (key.equals(n.getKey())) {
            n.setObj(value);
            size++;
        } else {
            while (null != n) {
                if (!key.equals(n.getKey())) {
                    n = n.getNext();
                } else {
                    n.setObj(value);
                    return (V)n.getObj();
                }
            }
            n = array[nums];
            while (null != n) {
                if (n.getNext() == null) {
                    Node node = new Node(key, value);
                    n.setNext(node);
                    size++;
                    return (V)n.getObj();
                } else n = n.getNext();
            }

        }

        return null;
    }

    @Override
    V remove(K key) {
        int nums = key.hashCode() % cap;
        if (array[nums] == null) {
            return null;
        }
        if (array[nums].getKey().equals(key)) {
            if (array[nums].getNext() == null) {
                array[nums] = null;
                size--;
                return null;
            } else array[nums] = array[nums].getNext();

        } else {
            Node n;
            n = array[nums];
            while (null != n.getNext()) {
                if (!key.equals(n.getNext().getKey())) {
                    n = n.getNext();
                } else {
                    if (n.getNext().getNext() == null) {
                        n.setNext(null);
                        size--;
                        return null;
                    } else {
                        n.setNext(n.getNext().getNext());
                        size--;
                        return null;
                    }
                }
            }
        }

        return null;
    }

    private void put01(K key, V value, Node[] array1) {
        Node n;
        int nums = key.hashCode() % cap;
        if (array1[nums] == null) {
            array1[nums] = new Node<>(key, value);
            return;
        }
        n = array1[nums];
        if (key.equals(n.getKey())) {
            n.setObj(value);
        } else {
            while (null != n) {
                if (!key.equals(n.getKey())) {
                    n = n.getNext();
                } else n.setObj(value);
            }
            n = array1[nums];
            while (null != n) {
                if (n.getNext() == null) {
                    Node node = new Node(key, value);
                    n.setNext(node);
                } else n = n.getNext();
            }

        }

    }

    private boolean judgmentCapacity() {//判断是否满足扩容条件扩容
        double nums = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i] != null) nums++;
        }
        if (nums / anInt >= array.length) {
            cap = cap * 2;
            Node<K, V>[] array1 = new Node[cap];
            Node n;
            for (int i = 0; i < array.length; i++) {
                if (array[i] == null) {
                    continue;
                } else {
                    n = array[i];
                    while (true) {
                        if (n.getNext() != null) {
                            K key = (K) n.getKey();
                            V value = (V) n.getObj();
                            put01(key, value, array1);
                            n = n.getNext();
                        } else break;
                    }
                }
            }
            array = array1;
            return true;
        }
        return false;
    }


    @Override
    void clear() {
    array=new Node[cap];
    size=0;
    }
}

然后就是put的实现原理:
结构是数组加链表的形式 数组也就是桶子里只存放链表的节点(也就是地址)
在这里插入图片描述
1.每次put进去先判断满不满足扩容条件 :在桶子装满2/3的时候进行扩容 扩容为之前的2倍 也就是数组长度要扩容为之前的两倍
2.调用方法计算哈希值 这里我采用最简单的计算方法:key用哈希值计算以后直接对数组长度除余 得到的余数对应桶子(数组下标) 如果该桶子为空直接将结点放入桶子。
3.如果不为空就遍历该桶子对应的链表 查看有没有key相同的节点 替换里面的vaue值。
4.如果没有找到相同key的节点,就将该桶子里的链表最后一个节点的后继节点设为 刚刚put的节点也就是setnext() 方法

@Override
    V put(K key, V value) {
        judgmentCapacity();
        Node n;
        int nums = key.hashCode() % cap;
        if (array[nums] == null) {
            array[nums] = new Node<>(key, value);
            size++;
            return null;
        }
        n = array[nums];
        if (key.equals(n.getKey())) {
            n.setObj(value);
            size++;
        } else {
            while (null != n) {
                if (!key.equals(n.getKey())) {
                    n = n.getNext();
                } else {
                    n.setObj(value);
                    return (V)n.getObj();
                }
            }
            n = array[nums];
            while (null != n) {
                if (n.getNext() == null) {
                    Node node = new Node(key, value);
                    n.setNext(node);
                    size++;
                    return (V)n.getObj();
                } else n = n.getNext();
            }

        }

        return null;
    }

然后就是get()的原理:
很简单
1.根据get进来的的key计算哈希值除余 找到对应的桶子如果桶子为空直接返回false
2.如果不为空就查找相同key的节点 然后返回value值。

@Override
    V get(K key) {
        Node n;
        int i = key.hashCode() % cap;
        if (array[i] != null) {
            n = array[i];
            while (null != n) {
                if (!key.equals(n.getKey())) {
                    n = n.getNext();
                } else return (V) n.getObj();
            }

        }

        return null;
    }

最重要的是扩容机制:
1.上面说了每次put了之后 必须先检查满不满足扩容条件 这里没有使用红黑树
2.遍历所有数组 判断有没有满足数组长度的2/3 如果满足就开始扩容
新建一个之前二倍长度的数组 然后把之前的hashmap里的值全都复制进来
3.将之前hashmap数组的指针指向这个新的数组 就完成了扩容。

private boolean judgmentCapacity() {//判断是否满足扩容条件扩容
        double nums = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i] != null) nums++;
        }
        if (nums / anInt >= array.length) {
            cap = cap * 2;
            Node<K, V>[] array1 = new Node[cap];
            Node n;
            for (int i = 0; i < array.length; i++) {
                if (array[i] == null) {
                    continue;
                } else {
                    n = array[i];
                    while (true) {
                        if (n.getNext() != null) {
                            K key = (K) n.getKey();
                            V value = (V) n.getObj();
                            put01(key, value, array1);
                            n = n.getNext();
                        } else break;
                    }
                }
            }
            array = array1;
            return true;
        }
        return false;
    }
;