1. equals介绍
Object中的equals方法用于检测一个对象是否等于另外一个对象,如果两个对象的引用相等,则两对象相等。
假设有下面的Staff类:
public class Staff{
private String name;
private int age;
private double salary;
public Staff(String name, int age, double salary){
this.name = name;
this.age = age;
this.salary = salary;
}
//......其他相关代码
public static void main(String[] args){
Staff s = new Staff("张三", 25, 8000);
Staff s2 = new Staff("张三", 25, 8000);
Staff s3 = s;
//输出为false
System.out.println(s.equals(s2));
//输出为true
System.out.println(s.equals(s3));
}
}
上面的输出结果原因为:Staff类没用重写Object的equals方法,默认需要引用相同,才能返回true。若想使equals是根据内容来进行比较的,则需要重写Object的equals方法。
public class Staff{
private String name;
private int age;
private double salary;
public Staff(String name, int age, double salary){
this.name = name;
this.age = age;
this.salary = salary;
}
//重写Object的equals方法
@Override
public boolean equals(Object otherObject){
//若两个对象地址相同,返回true
if (this == otherObject) return true;
//若比较的对象是null,则返回false
if (otherObject == null) return false;
//另外的对象必须是Staff类型,若可以接受其子类型则使用 instanceof
if (this.getClass() != otherObject.getClass()) return false;
//进行强致类型转换
Staff other = (Staff)otherObject;
//若name、age、salary相同则返回true. 对象之间用equals进行比较,基本类型之间用==进行比较
return this.name.equals(other.name) && this.age == other.age && this.salary == other.salary;
}
//......其他相关代码
public static void main(String[] args){
Staff s = new Staff("张三", 25, 8000);
Staff s2 = new Staff("张三", 25, 8000);
Staff s3 = s;
//此时输出为true,对象内容相同,则认为是相等。
System.out.println(s.equals(s2));
//输出为true
System.out.println(s.equals(s3));
}
}
若不太了解Java的基本数据类型,请阅读:Java数据类型相关知识
在用户自定义类中重写equals方法可以根据需求来对类对象进行相等性判断。
当上面的name为null时,调用this.name.equals(other.name)即在一个null对象上面调用方法,会出现的错误,避免错误则需把上面的equals方法改为:
public boolean equals(Object otherObject){
//若两个对象地址相同,返回true
if (this == otherObject) return true;
//若比较的对象是null,则返回false
if (otherObject == null) return false;
//另外的对象必须是Staff类型,若可以接受其子类型则使用 instanceof
if (this.getClass() != otherObject.getClass()) return false;
//进行强致类型转换
Staff other = (Staff)otherObject;
//使用Objects类的静态方法equals来判断对象是否相等。基本数据类型可以直接使用==进行判断。
return Objects.equals(this.name, other.name) && this.age == other.age && this.salary == other.salary;
Objects.equals(a, b)方法接收两个参数,若两个参数都为null则返回true,其中一个为null返回false,不为null则调用a.equals(b);
拓展:Java语言规范要求equals方法具有下面的特性:
- 自反性:对于任何的非空引用x, x.equals(x)应该返回true;
- 对称性:对于任何引用x和y,当且仅当y.equals(x)返回true时,x.equals(y)返回true。
- 传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,x.equals(z)也应该返回true。
- 一致性:如果x和y引用对象没有发生变化,反复调用x.equals(y)应该返回同样的结果。
- 对于任意的非空引用x,x.equals(null)应该返回false。
2. hashCode介绍
散列码(hash code) 是由对象导出的一个整型值。散列码是没用规律的。如果x和y是两个不同的对象,x.hashCode() 与 y.hashCode() 基本上是不会相同。在Object中每个对象都有一个默认的散列码,其值是由对象的存储地址得出的。(String类型除外)
注:字符串的散列码是由内容推到出来的。
如果重写了equals方法,就必须为用户可能插入散列表的对象重新定义hashCode方法。
public class Staff{
//...
public int hashCode(){
return 7*name.hashCode() + 11*Integer(age).hashCode() + 13*Double(salary).hashCode();
}
上面的age和salary为基本数据类型,需转换为包装类型才能调用hashCode方法。
为防止name为null,则可改为:
return 7*Objects.hashCode(name) + 11*Integer(age).hashCode() + 13*Double(salary).hashCode();
也可进一步简写为:
return Objects.hash(name, age, salary);