Java自定义编写HashMap的get和put方法

package com.fzq.hashmaptest;

/**
 * 手写HashMap的get方法和put方法
 */
public class MyHashMap<K, V> {
    private Node<K, V>[] table;
    private int size;

    static class Node<K, V> {
        int hash;
        K key;
        V value;
        Node<K, V> next;

        /**
         * 构造一个结点对象
         *
         * @param hash  哈希值
         * @param key   键
         * @param value 值
         * @param next  下一个结点的地址
         */
        public Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        /**
         * 重写Node方法的toString方法
         *
         * @return 返回键值对
         */
        @Override
        public String toString() {
            return "Node{" + "key=" + key + ", value=" + value + '}';
        }
    }

    public int size() {
        return size;
    }

    @SuppressWarnings("unchecked")
    public MyHashMap() {
        this.table = new Node[16];
    }

    public MyHashMap(Node<K, V>[] table, int size) {
        this.table = table;
        this.size = size;
    }

    /**
     * 重写toString方法,直接输出Map集合是会调用
     *
     * @return ""
     */
    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < table.length; i++) {
            Node<K, V> node = table[i];
            while (null != node) {
                stringBuilder.append(node.toString());
                stringBuilder.append("\n");
                node = node.next;
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 向MyHashMap添加一个键值对
     *
     * @param key   键
     * @param value 值
     * @return value,如果Key重复,则返回oldValue,如果Key不重复,则返回newValue
     */
    public V put(K key, V value) {
//        【第一步】:处理key为null的情况,如果添加键值对的key就是null,则将该键值对存储到table数组索引为0的位置
        if (key == null) {
            return putForNullKey(value);
        }
//        【第二步】:获得key对象的哈希值,如果添加的键值对不是null,则调用key的hashcode方法,获得key的哈希值
        int hash = key.hashCode();
//        【第三步】:获得键值对的存储位置,因为获得的哈希值在数组合法索引范围之外,因此我们就需要将获取的哈希值转化为[0,数组长度-1]范围的整数,
//        那么可以通过取模法来实现,也就是通过“哈希值 % 数组长度”来获得索引位置(i)。
        int index = Math.abs(hash % table.length);
        Node<K, V> node = table[index];
        if (null == node) {
            table[index] = new Node<K, V>(hash, key, value, null);
            size++;
            return value;
        }
//        【第四步】:将键值对添加到table数组中
//                当table[i]返回结果为null时,则键值对封装成Node对象并存入到table[i]的位置。
//                当table[i]返回结果不为null时,则意味着table[i]存储的是单链表。我们首先遍历单链表,如果遍历出来节点的key和添加键值对的key相同
//                那么久执行覆盖操作:如果遍历出来节点的key和添加键值对的key都不同,则将键值对封装为Node对象并插入到单链表末尾
        Node<K, V> prev = null;
        while (null != node) {
            if (node.key.equals(key)) {
                V oldValue = node.value;
                node.value = value;
                return oldValue;
            }
            prev = node;
            node = node.next;
        }
        prev.next = new Node<K, V>(hash, key, value, null);
        size++;
        return value;
    }

    /**
     * 如果添加键值对的key就是null,则将该键值对存储到table数组索引为0的位置
     *
     * @param value 值
     * @return 返回值
     */
    private V putForNullKey(V value) {
        Node<K, V> node = table[0];
//        如果table数值索引为0的位置没有数据,则新增一条数据
        if (null == node) {
            table[0] = new Node<K, V>(0, null, value, null);
            size++;
            return value;
        }
        Node<K, V> prev = null;
        while (null != node) {
            if (null == node.key) {
                V oldValue = node.value;
                node.value = value;
                return oldValue;
            }
            prev = node;
            node = node.next;
        }
        prev.next = new Node<K, V>(0, null, value, null);
        size++;
        return value;
    }

    /**
     * 通过key获取value
     *
     * @param key 键
     * @return 值
     */
    public V get(K key) {
        /*
         第一步:处理key为null的情况
          如果查询的key就是null,则在table数组索引为0的位置查询
         */
        if (null == key) {
            Node<K, V> node = table[0];
            if (null == node){
                return null;
            }
            while (null != node){
                if (node.key == null){
                    return node.value;
                }
                node = node.next;
            }
        }
        /*
          第二步:获得key对象的哈希值
          如果查询的key不是null,则调用key的hashCode方法,获得key的哈希值
         */
        int hash = key.hashCode();
        /*
          第三步:获得键值对的存储位置
          因为获得的哈希值在数组合法索引范围之外,因此我们就需要将获得的哈希值转化为[0,数组长度-1]范围的整数,
          那么可以通过取模法来实现,也就是通过"哈希值 % 数组长度"来获得索引位置(i)
         */
        int index = Math.abs(hash % table.length);
        /*
          第四步:遍历单链表,根据key获得value值
          如果table[i]返回的结果为null,则证明单链表不存在,直接返回null
          如果table[i]返回的结果不为null,则证明单链表存在,那么久遍历整个单链表,如果遍历出来的结点的key和查询的key相同,那么就返回遍历出来的结点的value值
          如果整个单链表遍历完毕,则遍历出来结点的key和查询的key都不相等,那么就证明查询key在链表中不存在,返回null
         */
        Node<K, V> node = table[index];
        if (null == node){
            return null;
        }
        while (null != node){
            if (node.key.equals(key)){
                return node.value;
            }
            node = node.next;
        }
        return null;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值