- Java中所有的类都继承了Object超类,因此每个对象都有equals()方法
/**源码:Object类中的equals()方法,不重写equals方法则默认继承以下方法
*/
public boolean equals(Object obj) {
return (this == obj);
}
- Object类中的equals方法用于检测一个对象是否等于另外一个对象。Object类中实现的equals方法确定两个对象应用是否相等。这是一个合理的默认行为:如果两个对象引用相等,这两个对象肯定就相等。对于很多类来说,这已经足够了。
- Java语言规范要求equals方法具有下面的特性:
1、自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
2、对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
3、传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
4、一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
5、对于任何非空引用值 x,x.equals(null) 都应返回 false。
- 代码示例一
1、创建实体类Student.java
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(String name) {
this.name = name;
}
}
2、创建测试类Test1.java
public class Test1 {
public static void main(String[] args) {
Student stu1=new Student("小明");
Student stu2=new Student("小明");
System.out.println(stu1.equals(stu2));
}
}
3、运行结果为false
因为上面测试类中的equals方法默认的是继承的Object中的,该默认方法只是比较两个对象引用是否相同,因为创建的是两个对象,所以比较结果是false即使里面的数据是相同的。
- 代码示例二
1、创建Student.java并重写equals和hashCode方法
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**此处为重写Object中默认equals方法,显然默认的equals方法是不满足我们的比较条件的,需要对
* 原有方法进行完善,第一个if是比较的两个对象引用是否相同,第二个if为比较两个对象中的数据
* 是否相同,显然两个对象的引用是不同的。但是在给name赋值相同的情况下,满足第二个if条件
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj==this){
return true;
}
if(obj instanceof Student){
Student sutdent=(Student) obj;
if(sutdent.getName().equals(this.name)){
return true;
}
}
return false;
}
/**当你重写了equals方法之后必须要重写hashCode方法,否则hashCode方法还是原来的
* 重写hashCode方法
* @return
*/
@Override
public int hashCode() {
return this.name.hashCode();
}
public Student(String name) {
this.name = name;
}
}
ps:注意上面类中重写hashCode方法部分,散列码(hash code)是由对象导出的一个整型值,可以是负数。散列码是没有规律的。由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值由对象的存储地址得出。如果重新定义了equals方法,就必须为用户可能插入散列表的对象重新定义hashCode方法
- hashcode的作用
利用HashSet/HashMap/Hashtable类来存储数据时,为了提高程序的效率,先进行hashcode的比较,如果不同,那没就不必在进行equals的比较了,这样大大减少了equals比较的次数,从而大幅度提高了效率。
JDK的API建议:equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。常规协定如下
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
上面的例子中,我们重写了equals方法,并规定只要对象的name属性值相同,两个对象就相等,很显然我们的目的可以轻松达到。但是我们没有重写hashCode方法,hashCode方法仍然返回原对象的内存地址,所以两个对象的hashCode值还是不相等,这就违反了hashCode 方法的常规协定。后果是,在某些利用对象hashCode值做索引的情况下,这样会造成混乱,相当于没有重写equals方法。
2、创建Test2.java
public class Test1 {
/**
* 用于测试重写equals方法之后,两个对象在值相同的情况下的比较结果。
* 下面代码返回值为true因为在Student类中重写了equals方法,如果用默
* 认的equals方法会返回false。
* @param args
*/
public static void main(String[] args) {
Student stu1=new Student("小明");
Student stu2=new Student("小明");
System.out.println(stu1.equals(stu2));
}
}
3、运行结果:true。因为在Student.java类中对equals方法进行了重写,仔细看Student类中重写的equals方法
PS:开发中容易报错的地方,在进行a.equals(b)的时候,如果a为null这个时候代码就会报空指针的异常,因此要将明确的常量值放在前面,这样如果b为null时,执行结果为false,但是不会报空指针异常。