Java中hashCode() 和 equals()的问题解答

一.equals() 的作用是什么?

equals() 的作用是 用来判断两个对象是否相等

equals() 定义在JDK的Object.java中。通过判断两个对象的地址是否相等(即是否是同一个对象)来区分它们是否相等。源码如下:

public boolean equals(Object obj) {
    return (this == obj);
}

既然Object.java中定义了equals()方法,这就意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。但是我们知道使用默认的equals()方法,等价于==方法。因此,我们通常会重写equals()方法:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。

下面我们根据类是否覆盖equals()方法来区分:

  • 若某个类没有覆盖equals()方法,当通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象(比较的对象的内存地址)。这时,等价通过==去比较这两个对象。

  • 若某个类覆盖类的equals()方法,当通过equals()比较两个对象是否相等时,若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。

下面我们举例来说明:

没有覆盖equals()方法的情况

public class Test{

    public static void main(String[] args) {

        Person p1 = new Person("张三"25);
        Person p2 = new Person("张三"25);
        System.out.printf(p1.equals(p2));
    }
}
private  class Person {
        int age;
        String name;

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

        public String toString() {
            return name + " - " +age;
        }
}

运行结果

false

结果分析

我们通过 p1.equals(p2) 来“比较p1和p2是否相等时”。实际上,调用的Object.java的equals()方法,即调用的 (p1==p2) 。它是比较“p1和p2是否是同一个对象”。
   而由 p1 和 p2 的定义可知,它们虽然内容相同;但它们是两个不同的对象!因此,返回结果是false。

覆盖equals()方法的情况

我们把Person 类重新equal(),如下:

@Override
public boolean equals(Object obj){  
  if(obj == null){  
  return false;  
}  

//如果是同一个对象返回true,反之返回false  
if(this == obj){  
   return true;  
}  

//判断是否类型相同  
if(this.getClass() != obj.getClass()){  
   return false;  
}  

Person person = (Person)obj;  
return name.equals(person.name) && age==person.age;  
}

运行结果

true

结果分析

我们重写了Person的equals()函数:当两个Person对象的 name 和 age 都相等,则返回true。因此,运行结果返回true。

二.equals() 与 == 的区别是什么?

equals() : 它的作用也是判断两个对象是否相等。

  • 类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。

  • 类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。

对于==

  • 基本数据类型 :byte,short,char,int,long,float,double,boolean。则直接比较其存储的”值”是否相等。

  • 引用数据类型(String,Date):当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址(确切的说,是堆内存地址)。

三.hashCode() 的作用是什么?

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。

hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。

虽然,每个Java类都包含hashCode() 函数。但是,仅仅当创建并某个“类的散列表时,该类的hashCode() 才有用(作用是:确定该类的每一个对象在散列表中

的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),类的hashCode() 没有作用。上面的散列表指的是:Java集合中本质是散列表

的类,如HashMap,Hashtable,HashSet。

综上所述:

hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

下面,我们以HashSet为例,来深入说明hashCode()的作用。

假设,HashSet中已经有1000个元素。当插入第1001个元素时,需要怎么处理?因为HashSet是Set集合,它允许有重复元素。将第1001个元素逐个的和前

面1000个元素进行比较”?显然,这个效率是相等低下的。散列表很好的解决了这个问题,它根据元素的散列码计算出元素在散列表中的位置,然后将元素插

入该位置即可。对于相同的元素,自然是只保存了一个。

由此可知,若两个元素相等,它们的散列码一定相等;但反过来确不一定。在散列表中

  • 如果两个对象相等,那么它们的hashCode()值一定要相同

  • 如果两个对象hashCode()相等,它们并不一定相等。

四.hashCode() 和 equals() 之间有什么联系?

1. 第一种 不会创建“类对应的散列表”

这里所说的“不会创建类对应的散列表”是说:我们不会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中,用到该类。例如,不会创建该类的HashSet集合。

在这种情况下,该类的“hashCode() 和 equals() ”没有半毛钱关系的!

这种情况下,equals() 用来比较该类的两个对象是否相等。而hashCode() 则根本没有任何作用,所以,不用理会hashCode()。

下面,我们通过示例查看类的两个对象相等 以及 不等时hashCode()的取值。

public class Person {

    private String name;
    private String sex;

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

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

//    @Override
//    public int hashCode() {
//        return Objects.hash(name, sex);
//    }
}

 public static void main(String[] args) {
        Person person=new Person("张三","男");
        Person person1=new Person("张三","男");
        System.out.println("person.hashCode():"+person.hashCode()+"t" +"person1.hashCode():"+person1.hashCode());
        System.out.println("equal:"+person.equals(person1));
    }

运行结果

person.hashCode():1639705018    
person1.hashCode():1627674070
equal:true

从结果也可以看出:personperson1相等的情况下,hashCode()也不一定相等。**

2. 第二种 会创建“类对应的散列表”

这里所说的“会创建类对应的散列表”是说:我们会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中,用到该类。例如,会创建该类的HashSet集合。

在这种情况下,该类的“hashCode() 和 equals() ”是有关系的:

如果两个对象相等,那么它们的hashCode()值一定相同。这里的相等是指,通过equals()比较两个对象时返回true。

如果两个对象hashCode()相等,它们并不一定相等。因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并

不一定能 得出键值对相等。

此外,在这种情况下。若要判断两个对象是否相等,除了要覆盖equals()之外,也要覆盖hashCode()函数。否则,equals()无效。

例如,创建Person类的HashSet集合,必须同时覆盖Person类的equals() 和 hashCode()方法。如果单单只是覆盖equals()方法。我们会发现,

equals()方法没有达到我们想要的效果。

代码实例:Person 如上没有重写hashcode()方法

public class Test {
    public static void main(String[] args) {
        Person person=new Person("张三","男");
        Person person1=new Person("张三","男");
        Person person2=new Person("张三","男");
        HashSet hashSet=new HashSet();
        hashSet.add(person);
        hashSet.add(person1);
        hashSet.add(person2);

        System.out.println("person.hashCode():"+person.hashCode());
        System.out.println("person1.hashCode():"+person1.hashCode());
        System.out.println("person2.hashCode():"+person1.hashCode());
        System.out.println("equal:"+person.equals(person1));


    }
}

运行结果

person.hashCode():1639705018
person1.hashCode():1627674070
person2.hashCode():1627674070
equal:true

结果分析

我们重写了Person的equals()。但是,很奇怪的发现:HashSet中仍然有重复元素:personperson1。为什么会出现这种情况呢?

这是因为虽然personperson1的内容相等,但是它们的hashCode()不等;所以,HashSet在添加personperson1的时候,认为它们不相等。

下面,我们同时覆盖equals() 和 hashCode()方法。

public class Person {

    private String name;
    private String sex;

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(name, sex);
    }
}

运行结果

person.hashCode():24052527
person1.hashCode():24052527
person2.hashCode():24052527
equal:true

结果分析

这下,equals()生效了,HashSet中没有重复元素。

比较personperson1,我们发现:它们的hashCode()相等,通过equals()比较它们也返回true。所以,personperson1被视为相等。

看到这里今天的分享就结束了,如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~

欢迎关注个人公众号 「JavaClub」,定期为你分享一些面试干货。


原文始发于微信公众号(阿福聊编程):Java中hashCode() 和 equals()的问题解答

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/105900.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!