使用HashSet 为什么要重写hashcode()和equals() 方法

原创
2020/06/18 18:50
阅读数 3.4K

使用HashSet 为什么要重写hashcode()和equals() 方法

Object.hashCode() 和 equals() 方法的用途

hashCode()方法和equals()方法的作用其实一样,在Java里都是用来对比两个对象是否相等一致。

hashcode 其实是对象物理地址返回的整数值,equals() 方法默认比较的就是两个对象的地址是否相同;所以equals() 相等的两个对象,hashCode 一定相同;

下边从两个角度介绍了他们的区别:一个是性能,一个是可靠性。他们之间的主要区别也基本体现在这里。

1、equals()既然已经能实现对比的功能了,为什么还要hashCode()呢?

因为重写的equals()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。

2、hashCode()既然效率这么高为什么还要equals()呢?

因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出(PS:以下两条结论是重点,很多人面试的时候都说不出来):

equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。

hashCode()相等的两个对象他们的equals()不一定相等,也就是hashCode()不是绝对可靠的。

HashSet 为什么要重写两个方法

HashSet 底层使用HashMap实现的,但是HashSet 有元素不可重复的原则。

如果类并没有重写两个方法,不能保证元素的的不可重复的原则,举例如下:

有一个类User

Class User {
  
  private int id;
  private String name;
  // set get 方法省略
}

public void test1() {

        User user1 = new User();
        user1.setId(3);
        user1.setName("ddd");

        User user2 = new User();
        user2.setId(3);
        user2.setName("ddd");

        HashSet set = new HashSet();
        boolean r1 = set.add(user1);
        boolean r2 = set.add(user2);

        System.out.println(r1);
        System.out.println(r2);
}

打印结果:

true
true

两个对象属性一样,但是依然还是添加进了set 集合,这不符合我们想要的不可重复结果。具体原因看HashMap的put()方法源码。

在判断元素是否已存在的时候:

  1. 要先进行当前链表头结点与新增加的节点的hash值判断是否相等。

  2. 进行key 值(HashSet的key就是存入对象,value 为Object present 的常量)的equals方法判断。

按照上面User1 和 User2 两个对象,hash值肯定不同,equals 方法比较两个对象的地址,均为false。所以Hashmap 认为两者不是相同的对象,所以都添加成功。这显然不符合我们的实际业务要求。所以我们要重写hashcode 和 equals 方法。只重写一个方法依然不满足。重写举例如下:

        @Override
        public int hashCode() {
            return id;
        }

        @Override
        public boolean equals(Object obj) {
            
            obj = (User) obj;
            
            return ((User) obj).id == this.id && ((User) obj).name == this.name;
        }

执行结果:

true
false

从结果上可以看出,user2没有添加成功,这符合我们的要求。(PS: 这里说明下,HashMap是不会处理重复不重复的,如果重复了直接将原值覆盖,并且将旧值返回,所以user2 从原理上说是覆盖掉了user1,但两个元素一样,所以HashSet 不可重复依然满足,HashSet的添加成功的判断是根据HashMap 的put 有没有返回值判断的,如果有说明旧值被覆盖了,但是提示用户添加失败,这只是从面上看上去是失败而已,其实是成功了。)

hashCode 和equals 方法的重写原则

hashCode和equals 1.只要重写equals,就必须重写hashCode 2.因为Set存储的是不重复的对象(根据hashCode和equals判断),所以Set储存的对象必须重写这两个方法 3.如果自定义对象作为Map的Key,必须重写hashCode和equals

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部