Java Custom HashMap

来源:互联网 发布:淘宝开店用什么软件好 编辑:程序博客网 时间:2024/04/29 01:15

我们都知道hashmap的数据结构是基于数组+链表,现在自己就仿照JDK里面的HashMpa来实现一个简易的自己的hashmap。主要考虑以下功能点:

  1. put:把值放入到Map中储存起来
  2. get:从Map中获取一个键值的值
  3. size:获取Map的储存数据的个数

1、定义接口 – MyMap

定义一个MyMap接口,用于实现简单的Map接口

MyMap.java

public interface MyMap<K, V> {    V put(K key, V value);    V get(K key);    int size();    interface Entry<K, V>{        K getKey();        V getValue();    }}

2、实现接口 – MyHashMap

实现自定义的MyHashMap.

MyHashMap.java

public class MyHashMap<K, V> implements MyMap<K, V> {    private final static int DEFAULT_INIT_CAPACITY = 16;    private final static float DEFAULT_LOAD_FACTOR = 0.75F;    private int capacity = DEFAULT_INIT_CAPACITY;    private float loadFactor = DEFAULT_LOAD_FACTOR;    private Node<K, V>[] table = null;    private int size = 0;    public MyHashMap(int capacity, float loadFactor){        if(capacity < 0){            throw new RuntimeException("capacity can less than 0, is " + capacity);        }        if(loadFactor <= 0 || loadFactor >1){            throw new RuntimeException("loadFactor error, is " + loadFactor);        }        this.capacity = capacity;        this.loadFactor = loadFactor;        table = new Node[this.capacity];    }    public MyHashMap(){        this(DEFAULT_INIT_CAPACITY, DEFAULT_LOAD_FACTOR);    }    public V put(K key, V value) {        if(size > capacity * loadFactor){            up2Size();        }        int index = getIndex(key);        Node<K, V> node = table[index];        size++;        if(node == null){            table[index] = newNode(key, value, null);        } else {            table[index] = newNode(key, value, node);        }        return value;    }    public V get(K key) {        int index = getIndex(key);        Node<K, V> node = table[index];        if(node == null){            return null;        }        return findValueByEqualKey(key, node);    }    public int size() {        return size;    }    private Node<K, V> newNode(K key, V value, Node<K, V> next) {        return new Node<K, V>(key, value, next);    }    /**     * 扩容     */    private void up2Size() {        Node<K, V>[] newTable = new Node[capacity * 2];        againHash(newTable);    }    /**     * 重新hash     * @param newTable     */    private void againHash(Node<K, V>[] newTable) {        List<Node<K, V>> nodes = new ArrayList<Node<K, V>>();        for(Node<K, V> node : table){            if(node == null){                continue;            }            findNodeByNext(node, nodes);        }        if(nodes.size() > 0){            // 重要设置Map的属性            capacity = capacity * 2;            size = 0;            table = newTable;            for(Node<K, V> node : nodes){                if(node.next != null){                    // 因为链表的next已经添加到List容器了,需要置null.                    node.next = null;                }                put(node.getKey(), node.getValue());            }        }    }    /**     * 获取链表下的所有节点     */    private void findNodeByNext(Node<K, V> node, List<Node<K, V>> nodes) {        if(node != null && node.next != null){            nodes.add(node);            findNodeByNext(node.next, nodes);        } else {            nodes.add(node);        }    }    /**     * 获取hash     */    private int getIndex(K key) {        int hashCode = key.hashCode();        int index = hashCode & capacity - 1;        return index < 0 ? -index : index;    }    /**     * 遍历节点下面的链表     */    private V findValueByEqualKey(K key, Node<K, V> node) {        if(key == node.getKey() || key.equals(node.getKey())){            return node.getValue();        } else {            if(node.next != null){                return findValueByEqualKey(key, node.next);            }        }        return null;    }    class Node<K,V> implements Entry<K, V>{        private K key;        private V value;        private Node<K, V> next;        public Node(K key, V value, Node<K, V> next){            this.key = key;            this.value = value;            this.next = next;        }        public K getKey() {            return key;        }        public V getValue() {            return value;        }        @Override        public String toString() {            return "Node{" +                    "key=" + key +                    ", value=" + value +                    '}';        }    }}

3、测试

写一个测试类,用于检测实现接口的正确性。

public class Test {    public static void main(String[] args) {        MyMap<String, String> map = new MyHashMap<String, String>();        for(int i = 0; i < 1000; i++){            map.put("key" + i, "value" + i);        }        System.out.println("测试是否每个值都放入到Map中,而且扩容的时候有没有丢掉数据");        for(int i = 0; i < 1000; i++){            String value = map.get("key" + i);            System.out.println("key : key" +  i + ", value : " + value);        }        System.out.println("map里面数据的个数为 : " + map.size());    }}

这里写图片描述

上面的图片只是截取了验证后面的结果,前面的value都是有值的。之前出现了错误,就是在扩容的时候没有把所有的元素添加进去。导致里面有些key的值是null.

4、总结

虽然上面的代码基本上实现了Map的功能,但是与JDK里面的HashMap比较还是存在很多不足点。归纳如下:

  1. 没有考虑key值为空的情况。
  2. 没有考虑用户使用有参构造器传值不是2的指数次幂
  3. 对于同一节点的链表过长没有考虑性能优化

So what.这只是一个Map的简易实现。

0 0
原创粉丝点击