理解hashmap的key是自定义类型为什么需要重写hashCode和equals

知道hashmap的key是自定义类需要重写hashCode和equals,是从面经知道的,当时也是只是去背而已,也尝试着去理解,但是没有实操做事很难受而且会有些问题。
最近写的一个项目时候基于Netty的节点注册事件系统,从中有一个需要自定义map的key值的环节,定义如下:

package NettyEventTouch.Nodes;

public final class Node{
    private final String node;
    private final String data;
    public Node(String node,String data){
        this.node = node;
        this.data = data;
    }

    public String getNode() {
        return node;
    }

    public String getData() {
        return data;
    }

    /*
        只是用node的原因是防止数据的改变而导致整个node的不可用
     */
    @Override
    public int hashCode() {
        return node.length()^(node.length()/2);
    }
 //按照面经的做法,一开始的自以为
    public boolean equals(Node node1) {
        return this.getNode().equals(node1.getNode());
    }

//    @Override
//    public boolean equals(Object obj) {
//        return this.getNode().equals(((Node)obj).getNode());
//    }

    @Override
    public String toString() {
        return "Node{" +
                "node='" + node + '\'' +
                ", data='" + data + '\'' +
                '}';
    }
}

简单的测试:

package NettyEventTouch;

import NettyEventTouch.Nodes.Node;

import java.util.HashMap;

public class test {
    public static void main(String[] args) {
        Node node = new Node("123","123456789");
        HashMap<Node,String> map = new HashMap<>();
        map.put(node,"123");
        Node node2 = new Node(node.getNode(),"11111111");
        if (map.containsKey(node2)){
            String s = map.get(node2);
            System.out.println(s);
        }
    }
}

结果可想而知并没有进入if语句,所以失败,但是为什么是被需要追寻的:通过debug追到map中的这样一段代码:

 /**
     * Implements Map.get and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
           //开始判断
            /**
           1.先看看hash是不是一样的,如果一样的,那么继续,上面的代码中只是简单的使用了node.length()^(node.length()/2)、
          来作为hash值,由于在test中node的node值没有改变所以hash是不变的,所以这个判断视为真
           2.来看后半段的逻辑,如果map的key是一样的,那么为真,但是这个是不可能的,因为node2是新创建出来的,对于非基本类型那么==比较的就是累的地址信息,所以显然两个对象不是一个地址,所以这个判断为false,后面的就是比较key的值了,先判断key是否为空,显然不为空,所以判断key.equals(k),这个但是Node里的equals并没有继承Object的equals,因为Node中的equals的参数类型变了,所以这里不会被引用到素以这里调用的是Object的equals,其实就是==,那么理所当然是false的。
	        */    
       
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
                
       /**
           处理key冲突时的数据的获取
           1.先判断是不是红黑树节点,如果是那么去红黑树里取值
           2.如果不是的话那么就挨个的取得下一个节点并判断其是否符合要求
	   */
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

从上面的可以看出来了,由于我的equals没有实现Object的equals,所以在内部调用的时候没有调用到,所以需要改下代码,也即被我注释掉的那个:

    @Override
    public boolean equals(Object obj) {
        return this.getNode().equals(((Node)obj).getNode());
    }

这个就可以了,所以这里可以验证了面经的正确,如果hashmap的key是自定义类那么就需要重写hashCode和equals,不然会出现数据是一样的,但是hashmap会报没有key值的问题。

结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值