• 你知道不同时重写 equals 和 hashCode 会怎样呢?


    一、我不同时重写又能如何呢?

    我只能说只要你不碰到这几个主,你也没什么事的!

    1)为什么不能遇到它们几个呢?

      因为它们几个会用到 hashCode 方法。

    2)他们用hashCode方法来干嘛?

      hashCode 方法是根据对象的地址生成的一个 int 整数,默认它和地址一一对应的,如果不重写,那么只有对象地址一样的情况下,哈希值才相等【实际不存在】

      equals 默认用来比较地址是否相同,但当集合中元素增多时,再使用 equals 判断,效率是比较低的;而哈希值是可以快速定位到指定的元素的,所以默认 Java 就使用哈希值来比较定位,因此有了 Object.hashCode 的约定;后来根据 hash 值定位到对象时,重写 equals() 方法根据对象的某几个属性确定是否是同一个对象。

      Set 怎么实现存储不重复的元素的?HashMap 怎么判断相同的 key 的?有兴趣可去深入了解一下。

    二、例子

    小王在「堆」中有两套房产,这两套房产位于不同的地址。现在我想要判断这两套房子是否是同一个主人?

    于是我去问Object,而Object告诉我这两套房产不是一个人的!

    我:为什么呢?

    Object: equals告诉我两套房子离了十万八千里,在不同的地方(地址),当然不是同一个人了。

    我:这逻辑……(不符合我们常规的认知啊)

    既然这样,那我只能重写equals了

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || this.getClass() != o.getClass()) return false;
        User user = (User) o;
        return username.equals(user.username) && idcard.equals(user.idcard);
    }

    哈哈,好啦,现在equals终于知道这两个房子是同一人的啦!

    然而在房产管理局(HashMap)我得到一个消息:小王只要一套房产!

    WTF!我白干了!

    房产管理局(HashMap): 不信你看!

    private static HashMap<User, Integer> roomManager = Maps.newHashMap();
    
    public static void main(String[] args) {
        User user1 = new User("小王", "7218");
        countRoom(user1);
        System.out.println(user1.toString());
        User user2 = new User("小王", "7218");
        countRoom(user2);
        System.out.println(user2.toString());
    
        for (User key : roomManager.keySet()) {
            System.out.println("key = " + key + ", count = " + roomManager.get(key));
        }
    }
    
    private static void countRoom(User user) {
        boolean exist = roomManager.containsKey(user);
         if (exist) {
            Integer count = roomManager.get(user);
            roomManager.put(user, count + 1);
        } else {
            roomManager.put(user, 1);
        }
    }
    @AllArgsConstructor
    @NoArgsConstructor
    static class User {
        private String username;
        private String idcard;
    }

    结果展示:

    com.base.base.hash_equals.HashCodeEquals$User@6f496d9f      // user1 地址
    com.base.base.hash_equals.HashCodeEquals$User@723279cf      // user2 地址
    key = com.base.base.hash_equals.HashCodeEquals$User@6f496d9f, count = 1
    key = com.base.base.hash_equals.HashCodeEquals$User@723279cf, count = 1

    遇到你真是倒霉了,原来房产管理局(HashMap)使用了hashCode来计算的!想要正确的统计小王的房产只能重写hashCode方法了。

    @Override
    public int hashCode() {
        return Objects.hash(username, idcard);
    }

    此时,他们统计终于对了!!!

    三、如何重写 equals 与 hashCode

    我就不写出常说的那些约定性质了,写了也记不住。说说如何避免违反这些约定:

    1、重写equals

    •     通过==判断是否是同一个引用

    •     通过instanceof判断是否是相同类型

    •     把参数转为正确的类型

    •     对比双方各个属性值是否相同

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || this.getClass() != o.getClass()) return false;
        User user = (User) o;
        return username.equals(user.username) && idcard.equals(user.idcard);
    }

    2、重写hashCode

    hashCode方法应该为“不相等的对象产生不相等的哈希值”

    一般计算是根据你 equals 中用来比较的属性的 hashCode 组合计算的,不过目前JDK和一些类库已经给我提供了很好的重写方式,我们可不必去深究其中算法。

    方式一:

    @Override
    public int hashCode() {
        return Objects.hash(username, idcard);
    }

    使用了JDK自带Objects提供的静态方法。

    方式二:

    @EqualsAndHashCode    // 使用lombok中的注解,底层依然重写了对象的 hashCode 和 equals 方法
    static class User {
        private String username;
        private String idcard;
    }

    问题1:为什么已经重写了 hashCode() 方法,往往也是根据对象的 equals() 方法需要比较的属性进行重写了,就能确定相同属性值的对象 hash 值一样【地址一样】,为什么还需要重写 equals() 方法呢?

    解答1:相同属性值的不同对象这样重写的 hashCode() 方法地址一定是相同的,但是在比较两个对象是否相同时,需要调用 equals() 方法的,然后根据对象的属性值是否相同然后再判定。所以说,hashCode() 和 equals() 方法一定是同时出现的。

    注意:在测试的过程中,lombok 在类上加 @Data 注解时,@Data 默认已经重写了类的 toString() 方法,根据调用对象的 getter() 方法进行组装的,当对象的 get() 方法设计到计算时,会遇到一些坑,往大家谨记这一点。

    参考博客地址:Lombok的大坑!!@Data重写的toString特性 

  • 相关阅读:
    Android中各级目录的作用
    轻量级java开发(一)-Hibernate 安装
    Eclipse 安装插件
    Eclipse超级完美汉化教程
    JAVA中extends 与implements区别
    Java基础语法总结
    C#笔试题面试题锦集(全)总20篇
    Nginx集群
    Redis 集群方案
    MS Sql Server 中主从库的配置和使用介绍
  • 原文地址:https://www.cnblogs.com/blogtech/p/14680384.html
Copyright © 2020-2023  润新知