一.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
从结果也可以看出:person和person1相等的情况下,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中仍然有重复元素:person 和 person1。为什么会出现这种情况呢?
这是因为虽然person 和person1的内容相等,但是它们的hashCode()不等;所以,HashSet在添加person和person1的时候,认为它们不相等。
下面,我们同时覆盖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中没有重复元素。
比较person和person1,我们发现:它们的hashCode()相等,通过equals()比较它们也返回true。所以,person和person1被视为相等。
看到这里今天的分享就结束了,如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~
欢迎关注个人公众号 「JavaClub」,定期为你分享一些面试干货。
原文始发于微信公众号(阿福聊编程):Java中hashCode() 和 equals()的问题解答
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/105900.html