HashMap重写(1)HashMap实现了put()方法增加键值对
马上过年了,很感谢各位小老弟的关注哦
2018年的jdk集合框架专栏还有一些没写完,这几天刚好赶一下,不能再拖了。前面的重写过ArrayList和LinkedList,有木有很有意思呀~ 如果觉得很有意思就对了,接下来我们来拜访下HashMap大爷。

咱们先来分析一下HashMap的数据结构,这里我画了一张图:
HashMap重写(1)HashMap实现了put()方法增加键值对
这个图其实很简单,但是实际实现起来就很麻烦了。
HashMap就是数组和链表的结合体,先是根据hash值找到Entry[ ]数组的索引,hash值相等的键值对将会存到同一个数组索引的位置上。然后再根据key值找链表的位置,对应的存到链表的表尾。

很简单有没有,HashMap就这样巧妙的利用了数组方便寻址的优点,也利用了链表方便删除和插入的优点。

我们可以这样理解,数组的作用是先确定一个大概的范围,这样就不用像数组一样,操作一个数,一定要遍历完。然后链表是在数组确定了位置的基础上细分,这样就在一定程度上大大提高了效率! 当然jdk8中,当链表长度大于8,链表会自动变成红黑树。

明人不说暗话,我们先来实现一下put()方法,上代码!!!

package Study.Collection;

/**
 * <p>Description: 自定义一个HashMap
 * 实现了put方法增加键值对,并解决了键重复的时候覆盖相应的节点</p>
 * @author zhangyan
 * @date 2019/1/28 20:07
 */
public class YanHashMap {

    /**
     * 位桶数组。bucket  array
     */
    Node2[] table;

    /**
     * 存放的键值对的个数
     */
    int size;

    /**
     * 定义构造函数
     */
    public YanHashMap() {
        //长度一般定义成2的整数幂
        table = new Node2[16];
    }

    /**
     * put方法
     * @param key
     * @param value
     */
    public void put(Object key, Object value) {
        //定义了新的节点对象
        Node2 newNode = new Node2();
        newNode.hash = myHash(key.hashCode(), table.length);
        newNode.key = key;
        newNode.value = value;
        newNode.next = null;

        /**
         * temp是对应hash值的节点
         */
        Node2 temp = table[newNode.hash];

        //正在遍历的最后一个元素
        Node2 iterLast = null;
        boolean keyRepeat = false;

        if (temp == null) {
            //此处数组元素为空,则直接将新节点放进去
            table[newNode.hash] = newNode;
            size++;
        } else {
            //此处数组元素不为空,则遍历对应链表,对链表进行操作
            while (temp != null) {

                //判断key如果重复,则覆盖
                if (temp.key.equals(key)) {
                    keyRepeat = true;
                    //只是覆盖value即可,其他的值(hash,key,next)保持不变
                    temp.value = value;
                    //覆盖之后就不用遍历链表后面的节点
                    break;

                } else {
                    //key不重复,则遍历下一个。
                    iterLast = temp;
                    temp = temp.next;

                }
            }

            //没有发生key重复的情况,则添加到链表最后一个节点
            if(!keyRepeat){
                iterLast.next = newNode;
                size++;
            }
        }
    }

    /**
     * 返回Hash值
     * @param v
     * @param length
     * @return
     */
    public static int myHash(int v, int length) {
 //		System.out.println("hash in myHash:"+(v&(length-1)));		//直接位运算,效率高
 //		System.out.println("hash in myHash:"+(v%(length-1)));		//取模运算,效率低
        return v & (length - 1);
    }

    //测试
    public static void main(String[] args) {
        YanHashMap m = new YanHashMap();
        m.put(10, "aa");
        m.put(20, "bb");
        m.put(30, "cc");
        //测试key值相同,覆盖value是否成功
        m.put(20, "jiajia");

        // 找几个hash值相等的数测试链表
        // 测试hash值相同的情况下,形成链表是否成功
        m.put(53, "gg");
        m.put(69, "hh");
        m.put(85, "kk");
        System.out.println(m);
    }

}

节点

 public class Node2 {

        int  hash;
        Object  key;
        Object  value;
        Node2  next;
    }

当然这里还没有重写toString()方法,所以想查看集合中的数据,只能debug了

存入集合中的数据:
HashMap重写(1)HashMap实现了put()方法增加键值对
生成的链表:
HashMap重写(1)HashMap实现了put()方法增加键值对

相关文章: