一.equals的作用及与 == 的区别
1.equals通常用来比较两个对象的内容是否相等;
2.==用来比较两个对象的地址是否相等,equals方法默认等同于“==”;
3.Object类中的equals方法定义为判断两个对象的地址是否相等,地址相等则认为是对象相等。这也就意味着,我们新建的所有类如果没有复写equals方法,那么判断两个对象是否相等时就等同于“==”,也就是两个对象的地址是否相等。
public boolean equals(Object obj) {
return (this == obj);
}
二.重写equals和hashcode方法
未重写前测试:
package com.hmi.entity;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
package com.hmi.test;
import com.hmi.entity.Person;
public class EqualsTest {
public static void main(String[] args) {
Person p1 = new Person("小明",18);
Person p2 = new Person("小明",18);
System.out.println(p1.equals(p2));
System.out.println(p1==p2);
System.out.println(p1.hashCode()==p2.hashCode());
}
}
输出结果:
重写后的测试:
@Override
public boolean equals(Object obj) {
//如果为同一对象的不同引用,则返回true
if (this == obj) {
return true;
}
//如果传入对象为空,或者俩对象属于不同的类型。则返回false
if (obj == null || this.getClass() != obj.getClass()) {
return false;
}
//对象类型相同,则判断里面的内容是否相同
Person p = (Person) obj;
return this.getName().equals(p.getName())
&& this.getAge() == p.getAge();
}
@Override
public int hashCode() {
//生成一个 int 类型的变量 result,并且初始化一个值,比如15
int result = 15;
//JVM里最有效的计算方式就是进行位运算
// 31 * i = (i << 5) - i(左边 31*2=62,右边 2*2^5-2=62)
// 两边相等,JVM可以高效的进行计算
result = 31 * result + (name == null ? 0 : name.hashCode() + age);
return result;
}
输出结果:
三.重写equals方法为什么还要重写hashcode?
equals方法必须要满足以下几个特性:
1.自反性:x.equals(x) == true,自己和自己比较相等
2.对称性:x.equals(y) == y.equals(x),两个对象调用equals的的结果应该一样
3.传递性:如果x.equals(y) == true y.equals(z) == true 则 x.equals(z) == true,x和y相等,y和z相等,则x和z相等
而如果某个类没有重写hashcode方法的话,equals判断两个值相等,但是hashcode的值不相等。对于一些集合就能产生冲突,比如HashMap,HashSet。
HashMap底层是由数组加链表组成的,hashcode就是数组的下标,如果不重写hashcode方法,则相同的对象会生成不同的hashcode。当插入到散列表中的时候相同的对象就会被插入,这是不符合规定的。我们知道向HashMap中插入相同值的时候会出现覆盖。
HashSet是基于HashMap实现的,HashSet中的元素都存放在HashMap的key上面,而value中的值都是统一的一个private static final Object PRESENT = new Object();。在HashSet中,因为value值没有用,也就不存在修改value值的说法,因此往HashSet中添加元素,首先根据哈希算法判断元素(也就是key)是否存在,如果不存在这插入,如果存在就不插入,这样HashSet中就不存在重复值。如果hashcode相同,那么相同的元素会被插入到HashSet中,不符合规定。
在没有重写hashcode的情况下,往HashSet里,添加两个相同的对象:
package com.hmi.test;
import java.util.HashSet;
import com.hmi.entity.Person;
public class HashSetTest {
public static void main(String[] args) {
Person p1 = new Person("小明",18);
Person p2 = new Person("小明",18);
HashSet hs = new HashSet<Person>();
hs.add(p1);
hs.add(p2);
System.out.println("HashSet.size="+hs.size());
}
}
输出结果:
显然不符合规定,重写hashcode后:
这就是为什么重写equals方法也一定要重写hashcode方法的原因。