equals
equals比较两个对象的内容是否相等,准确的说是用户或者需求认为两个对象相等两个对象就相等,比如下面两个类:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 我们可以认为当name和age都相等时两个对象是相等的
*/
@Override
public boolean equals(Student student) {
return this.age == student.age && this.name.equals(student.name);
}
}
public class Human {
private String name;
private String gender;
public Human(String name, String gender) {
this.name = name;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
/**
* 我们可以认为当只要性别gender相等时两个对象就是相等的
* 当然一般不会有这样的比较需求但是代码可以写成这样
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Human human = (Human) o;
return this.gender.equals(human.gender);
}
}
但Java内有个规定,当使用equals对比两个对象得到的值相等时,hashCode必须相等(当重写equals方法是必须重写hashCode方法),请看下面对hashCode的理解,所以上面两个类都不符合规范
hashCode
hashCode方法的存在主要是为了对象存放在使用了散列(hash)表的数据结构(例如HashMap)时能够使用hashCode直接获取散列(hash)值,hash值用于定位对象在hash表的位置,在Object中hashCode是一个本地方法,是对对象的内存地址计算得出的一个值,可以看成就是内存地址
那么回到当使用equals对比两个对象得到的值相等时,hashCode必须相等这个规定,我们或者需求认为两个对象相等的话肯定是希望它们内部的属性值相等,并且在hash表的数据结构中定位到的位置(桶)是一样的,有人可能会说我这个类不需要用在想HashMap这类hash表的数据结构中,那可以不重写hashCode吗?当然不行,因为你这个类可能在别人使用时放在了HashMap这类数据结构中,或者说说不准你未来要用到,因此就有了这个规定,因此规范的equals和hashCode重写应该像下面这样(IDEA自动生成)
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void test(Student student) {
String test = student.name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name); // 属性值是对象类型则递归调用属性值equals方法
}
@Override
public int hashCode() {
return Objects.hash(name, age); // 根据name和age生成hash值,name和age相等则hashCode相等
}
}
等号==
等号比较的就是两个变量指向的引用是否是同一个引用,也就是比较内存地址
总结
- 如果两个对象是同一个对象,那么使用==比较得到的值一定为true,equals的返回值也一定为true,hashCode也一定相等
- 如果两个对象不是同一个对象(进行两次new操作),那么==比较得到的一定位false,equals的值取决于equals如何重写的,通常来说如果内部属性值都相等则equals返回true,而hashCode不一定为相等,但为了能够在使用hash表的数据结构时不出错,人为规定必须重写hashCode方法,使得equals为ture时hashCode必须相等