equal()和hashcode()方法简析

简介: 由于equal()和hashcode()是object中的方法,所以每个类中都有这两个方法,但在实际应用中往往需要重写这两个方法。 重写equal()和hashcode()方法假设场景:java中的Set集合的特性之一是会去除相同的元素。

由于equal()和hashcode()是object中的方法,所以每个类中都有这两个方法,但在实际应用中往往需要重写这两个方法。

重写equal()和hashcode()方法
假设场景:java中的Set集合的特性之一是会去除相同的元素。假设在Set集合中存学生对象,同一个人只能在Set集合中存一次,判断一个学生是否是同一个人的依据为:姓名相同,年龄相同,即为同一人。
编写一个Student类:

public class Student {
    private String name;
    private Integer age;

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

       //todo 添加get/set 方法

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

编写一个测试类:

public class SetTest {

    /**
     * 假设一场景:判断一个学生是否是同一个人的依据为:姓名相同,年龄相同,即为同一人
     * @param args
     */
    public static void main(String [] args){

        Set set = new HashSet();
        set.add(new Student("xiaoming",22));
        set.add(new Student("liangliang",24));
        set.add(new Student("xiaoming",22));
        set.add(new Student("daming",23));
        set.add(new Student("xiaoming",23));

        for (Iterator it =set.iterator();it.hasNext();){
            System.out.println(it.next());
        }
    }
}

测试结果:
image
显然,结果中出现两个xiaoming,年龄都为22,应该判断为一个人。出现这个结果是因为new出的每一个对象,哈希值是不同的, 想要实现预定的需求,必然要重写equal方法和hashcode方法。
在student类中重写这两个方法:

@Override
    public int hashCode() {
        return this.name.hashCode()+age * 31;
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj)
            return true;
        if(!(this instanceof Student)){
            throw  new ClassCastException("类型不一样");
        }
        Student stu = (Student) obj; 
        return this.age == stu.age && this.name == stu.name;
    }

重写equal方法和hashcode方法有多种,可以根据自己的实际需求来指定合适的重写方法。
测试结果:
image

实现所需要的结果。

思考:为什么要重写equal和hashcode方法,这两个方法的调用机制是什么?

java中引入hashcode的方法主要就是为了查找方便,如果是一个数组去实现,想要找到其中一个值,就需要一个一个去比较,在数据量很大的情况下,性能会特别差,用hashcode方法可以快速找到存储的位置。那是否只重写hashcode()方法就可以呢?答案是否定的。只覆写hashcode 的方法,还是得不到预期的结果,因为同名同年龄得到的哈希值是一样的,当hash值一样时,就会去比较equal方法,此时调用的是object中的equal()方法,比较的是地址,都是新new出对象,地址不一样,所以equal返回为false,判断出两个学生不是同一人,所以要同时覆写equal方法。

这两个调用机制是什么呢,是先调用equal()方法,还是先调用hashcode()方法,接下来做个小实验,在这两个方法中分别打印出调用的对象:


  @Override
    public int hashCode() {
        System.out.println(this.getName()+"调用hashcode方法:"+this.name.hashCode()+age * 31);
        return this.name.hashCode()+age * 31;
      //  return age ;
    }
    @Override
    public boolean equals(Object obj) {

        if(this == obj)
            return true;
        if(!(this instanceof Student)){
            throw  new ClassCastException("类型不一样");
        }
        Student stu = (Student) obj;
        System.out.println(this.getName()+"调用equal方法" +stu.getName());
        //此equal()方法为String中的方法
        return this.age == stu.age &&  this.name.equals( stu.name);
    }

测试结果:
image

所以,在比较是否为同一个人时,首先会调用它的hashcode()方法,只有当hashcode()值一样是才回去调用equal()方法。第二个xiaoming是先调用hashcode()方法,发现和第一个xiaoming的哈希值是星等的,才再去比较equal()方法。这种机制会减少很多比较,提升效率。

如果两个对象的hashcode值不同,则必是两个不同的对象;但,两个不同的对象所产生的hashcode值是可能一样的,称为哈希碰撞。

最后欣赏下IDEA自动生成的equal()和hashcode()方法:


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name) &&
                Objects.equals(age, student.age);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
目录
相关文章
|
存储 Java
【面试题精讲】为什么重写equals时必须重写hashCode方法?
【面试题精讲】为什么重写equals时必须重写hashCode方法?
|
2月前
|
设计模式 Java
结合HashMap与Java 8的Function和Optional消除ifelse判断
`shigen`是一位致力于记录成长、分享认知和留住感动的博客作者。本文通过具体代码示例探讨了如何优化业务代码中的if-else结构。首先展示了一个典型的if-else处理方法,并指出其弊端;然后引入了策略模式和工厂方法等优化方案,最终利用Java 8的Function和Optional特性简化代码。此外,还提到了其他几种消除if-else的方法,如switch-case、枚举行、SpringBoot的IOC等。一起跟随shigen的脚步,让每一天都有所不同!
38 10
结合HashMap与Java 8的Function和Optional消除ifelse判断
|
3月前
|
Java
【Java基础面试二十二】、为什么要重写hashCode()和equals()?
这篇文章解释了为什么需要重写`hashCode()`和`equals()`方法:因为Object类的`equals()`默认使用`==`比较,这在业务中通常是不够的,我们需要根据对象内容来比较相等性;同时,为了保持`hashCode()`与`equals()`的联动关系,一旦重写了`equals()`,通常也需要重写`hashCode()`。
【Java基础面试二十二】、为什么要重写hashCode()和equals()?
|
6月前
|
Java
JAVA中比较对象是否相等的方式是什么?为什么重写equals就一定要重写hashcode?百天百题(3/100)
JAVA中比较对象是否相等的方式是什么?为什么重写equals就一定要重写hashcode?
|
11月前
|
存储 算法 Java
史上最全的Java容器集合之equals 和 hashCode
史上最全的Java容器集合之equals 和 hashCode
60 0
|
存储 Java
引以为戒:避免在Set中使用未重写equals和hashCode的引用对象进行去重
在日常的Java开发中,我们经常会使用Set集合来实现去重操作,确保集合中不含有重复的元素。然而,如果使用未重写equals()和hashCode()方法的引用对象进行去重,可能会导致意外的行为,最近了在项目中就遇到了这个情况,让我们深入探讨这个问题,并引以为戒,确保正确实现去重操作。
66 0
引以为戒:避免在Set中使用未重写equals和hashCode的引用对象进行去重
|
Java 索引
【JAVA基础】equal和hashcode的区别
【JAVA基础】equal和hashcode的区别
|
存储 Java iOS开发
深究equals
在我们做项目的时候经常会将两个对象或者变量作比较,这时候会用到equals或者==,二者的区别在我们初学Java时就已经搞清楚了,一个比较的是值是否相等,另一个比较的是地址是否相等,但是equals真的只是比较两个值是否相等吗?如果是,那应该如何比较呢?
116 0
深究equals
|
存储 算法 Java
Java 细品 重写equals方法 和 hashcode 方法
Java 细品 重写equals方法 和 hashcode 方法
280 0
Java 细品 重写equals方法 和 hashcode 方法
hashCode和equal方法
hashCode和equal方法