在Java中,所有的类都继承自Object类,它是所有的始祖,但是我们不需要显示的书写extends Object.
equals方法
在JDK中,Object类的equals方法的实现如下:
public boolean equals(Object obj) {
return (this == obj);
}
就是简单的比较两个是否是引用的同一个对象即可。然而在工程中我们需要重新实现equals方法。
Java语言规范中要求equals方法需要符合以下要求:
自反性:对于任何的非空引用x,都有x.equals(x)返回true;
对称性:如果x.equals(y) == true, 那么y.equals(x) == true;
传递性:如果x.equals(y) == true, y.equals(z) == true,那么x.equals(z) == true;
一致性:如果x,y开始比较为true,在引用没有变化情况下,反复调用也为true;
对于任意的非空引用x,调用x.equals(null)都返回false;
但是在继承层次中的两个对象判断是否相等却比较麻烦,因为涉及到类型的转换。
如何才能编写完美的equals方法呢:
显式参数命名为 otherObject, 稍后需要将它强制转换成另一个叫做 other 的变量。
检测 this 与 otherObject 是否引用同一个对象:
if(this == otherObject) return true;
检测 otherObject 是否为 null , 如 果 为 null , 返 回 false。 这项检测是很必要的。
if(otherObject == null) return false;
比较 this 与 otherObject 是否属于同一个类。如果 equals 的语义在每个子类中有所改变, 就使用 getClass 检测:
if(getClass() != otherObject.getClass()) return false;
如果所有的子类都拥有统一的语义, 就使用 instanceof 检测:
if(!(otherObject instanceof ClassName)) return false;
转换为对应的类型变量:
ClassName other = (ClassName) otherObject;
开始比较对象中的每个属性,基本数据类型使用"=="判断,引用数据类型使用equals方法判断。
hashCode方法
散列码(hashCode)是由对象导出的一个整数值,hashCode是没有规律的。hashCode定义在Object类中,因此每个对象都有自己的hashCode,其值为对象的存储地址:
public native int hashCode();
如果在程序中重新定义了equals方法,那么就需要同时定义hashCode方法;方便用户将对象插入到Hash表中。
如何重新定义hashCode方法
hashCode方法应该返回一个整型数值(可以是负数),合理地利用各个属性的hashCode,以便让该对象产生的hashCode更加均匀。
@Override
public int hashCode() {
return name.hashCode() +
new Double(salary).hashCode() +
hreDate.hashCode();
}
更好的是可以避免null安全的方法Objects.hashCode方法,并使用各个属性:
@Override
public int hashCode() {
return Objects.hashCode(name)
+new Double(salary).hashCode() +
Objects.hashCode(hreDate);
}
直接针对各个属性值调用Objects.hash方法:
@Override
public int hashCode() {
return Objects.hash(name, salary, hreDate);
}
如果存在数组类型的属性,那么可以使用静态的Arrays,hashCode方法计算散列值,该散列值由数组的各个元素组成。
hashCode与equals方法的一致性
equals与hashCode的定义必须一致,如果x.equals(y) 返回true,那么x.hashCode与y.hashCode必须返回相同的值。
比如在Employee类中,equals方法比较的是ID,那么hashCode散列的时候也应该使用ID,而不是name或者salary。