面试题hashCode和equals

参考文献:

 看似简单的hashCode和equals面试题,竟然有这么多坑!

 q: 定义了student类,有age属性,然后a=new Student(10);b=new Student(10),现在有a==b,a.equals(b)则分别输出什么?

答:==是算述运算符,可以比较基本数据类型,也可以比较引用数据类型,如果比较的是基本数据类型比较的是值相等,如果比较的是引用数据类型,比较的是地址值是否相等。Equals默认比较的是地址值,具体怎样比较需要根据自己的要求进行自定义的比较方式。a==b输出false,a.equals(b)在自定义的类Student重写equals方法时如果重写了age属性则输出true,如果没有重写age属性,则为false;(注意:如果是java中继承了Object类的,已经重写过了Object中的equals()方法,则使用equals比较时就是输出true)。

import java.util.*;
class Student{
    String name;
    int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public class Main {
    public static void main(String[] args) {
        Student s1=new Student("mingming",12);
        Student s2=new Student("mingming",12);
        /*
        和equals()一样,Object里hashCode()里面只是返回当前对象的地址,
         如果是这样的话,那么我们相同的一个类,new两个对象,
         由于他们在内存里的地址不同,则他们的hashCode()不同且equals=false
         因此可以同时放到hashset
        */
        System.out.println(s1.hashCode()+"  "+s2.hashCode());
        System.out.println(s1.equals(s2));//false
        HashSet set = new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());//2

    }

}

结果输出:

1.不重写equals和hascode的结果:

2083562754  1239731077
false
2

2.只重写equals的结果 

2083562754  1239731077
true
2

3.重写equals和hascode之后的结果:

761311971  761311971
true
1

结论:

所以如果我们的对象要想放进hashSet,并且发挥hashSet的特性(即不包含一样的对象),则我们就要重写我们类的hashCode()和equals()方法了。像String,Integer等这种类内部都已经重写了这两个方法。

当然如果我们只是平时想对比两个对象 是否一致,则只重写一个equals(),然后利用equals()去对比也行的。

hascode相等,equals一定相等

重写equals+hascode  equals为true ,hascode相等

只重写equals                  equals为true ,hascode不一定相等

应用:

hash容器中,比如HashSet,HashMap,HashTable等等,要求对象不能重复,添加新的对象要进行对比

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

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

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

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

问题3:为什么要重写hascode()

避免出现,两个对象明明是相等(equals()=true),而hashCode却不一样。 如上的结果2.

2083562754  1239731077
true
2

造成的结果就是:

当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一个作为键值去查找他们的时候,则根本找不到。

 问题4:什么时候需要重写hascode()

一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode。

阿里巴巴开发规范也明确规定:

你可能感兴趣的:(java)