hashCode与equals
equals方法
Object#equals
java
public boolean equals(Object obj) {
return (this == obj);
}
equals是顶层方法,可以看出默认和==
一致,也就是比较内存地址是否相等。
equals作用
没有重写equals的情况
没有重写equals,效果其实等同于==
java
public class Sample1 {
public static void main(String[] args) {
Person p1 = new Person(20, "lisi");
Person p2 = new Person(20, "lisi");
System.out.println(p1.equals(p2));
}
private static class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
}
输出为false
没有重写equals,则比较的是对象的内存地址
重写了equals的情况
java
public class Sample2 {
public static void main(String[] args) {
Person p1 = new Person(20, "lisi");
Person p2 = new Person(20, "lisi");
System.out.println(p1.equals(p2));
}
private static class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if(o == null) {
return false;
}
if(this == o) {
return true;
}
if(this.getClass() != o.getClass()) {
return false;
}
Person p = (Person)o;
return name.equals(p.name) && age == p.age;
}
}
}
输出true
重写equals有几个必须要遵守的点:
- 对称性,x.equals(y)为true,则y.equals(x)也必须为true
- 反射性,x.equals(x)必须为true
- 类推性,x.equals(y)为true,y.equals(z)为true,那么z.equals(x)也必须为true
- 一致性,x.equals(y)为true,只要x和y内容不变,无论重复多少次x.equals(y),那么都必须为true;x.equals(不同类型)必须返回false
- 非空性,x.equals(null)都必须返回false
equals与==
的区别
==
:它的作用是判断两个对象的内存地址是否对象- equals:它的作用是判断两个对象是否相等,有两种情况
- 没有重写equals方法,等价于
==
- 重写了equals方法,比较两个对象的内容是否相等,若内容相等,则equals返回true
- 没有重写equals方法,等价于
hashCode方法
分两种情况
不会创建“类对应的散列表”
不会在HashSet、HashMap、Hashtable等这些哈希表数据结构容器中用到该类,则该类符合【不会创建“类对应的散列表”】类型
- 此时hashCode方法和equals方法是无关的
- 这种情况,equals用于表示两个对象是否相等,与hashCode无关
java
public class Sample3 {
public static void main(String[] args) {
Person p1 = new Person(20, "lisi");
Person p2 = new Person(20, "lisi");
Person p3 = new Person(30, "lisi");
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
}
private static class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if(o == null) {
return false;
}
if(this == o) {
return true;
}
if(this.getClass() != o.getClass()) {
return false;
}
Person p = (Person)o;
return name.equals(p.name) && age == p.age;
}
}
}
这种情况就是没在哈希结构的容器中使用到,所以跟hashCode没啥关系
会创建“类对应的散列表”
此种情况可以理解为会在哈希结构的容器中使用到,所以必然与hashCode有关,比如用到了HashSet
在这种情况下,hashCode与equals是有一定关系的
- 如果两个对象相等(equals为true),那么它们hashCode一定相等
- 如果两个对象hashCode相等,它们不一定相等,此种情况也叫哈希冲突
java
public class Sample4 {
public static void main(String[] args) {
Person p1 = new Person(20, "lisi");
Person p2 = new Person(20, "lisi");
Person p3 = new Person(30, "lisi");
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
}
private static class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public int hashCode() {
int i = name.hashCode();
return i % age;
}
@Override
public boolean equals(Object o) {
if(o == null) {
return false;
}
if(this == o) {
return true;
}
if(this.getClass() != o.getClass()) {
return false;
}
Person p = (Person)o;
return name.equals(p.name) && age == p.age;
}
}
}
也就是说之所以重写equals要重写hashCode,就是因为必须保证以哈希表为数据结构的容器(比如HashSet)添加元素时的正确性。