1、解释
我们知道,Object类提供了equals方法:
public boolean equals(Object obj) { return (this == obj); }
实现了对象地址的比较。也就是判断是否指向了同一对象。下列情况下,我们需要覆盖equals方法:
- 当需要判断是否逻辑相等,且超类还没有覆盖equals
这通常属于“值类”(value class)的情形。值类仅仅是一个表示值的类,例如Integer或者String 。程序员在利用equals方法来比较值对象的引用时,希望知道它们在逻辑上是否相等,而不是想了解它们是否指向同一个对象。String和八大基本类型的封装类都已经覆盖了equals方法。
在覆盖equals 方法的时候,必须要遵守它的通用约定:
- 自反性 (reflexive):对于任何非null的引用值x,x.equals(x)必须返回true
- 对称性(symmetric):对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true
- 传递性(transitive):对于任何非null的引用值x、y和z,如果x.equals(y)为true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true
- 一致性(consistent):对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回 false
- 非空性(Non-nullity):对于任何非null的引用值, x.equals(null)必须返回false
2、实现高质量equals的方法
- 使用==操作符检查”参数是否为这个对象的引用”
- 使用 instanceof 操作符检查”参数是否为正确的类型”
- 对于类中的关键属性,检查参数传入对象的属性是否与之相匹配
- 编写完equals方法后,问自己它是否满足对称性、传递性、一致性
- 重写equals时总是要重写 hashCode
- 不要将equals方法参数中的Object对象替换为其他的类型,在重写时不要忘掉@ Override 注解
3、最佳实践
在实际工作中,覆盖equals方法比较麻烦,通常我们使用IDE工具自带的生成equals功能:
private String loginId; private String password; private String name;
例如有以上属性的value object,使用工具生成的代码如下:
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ExampleBean other = (ExampleBean) obj; if (loginId == null) { if (other.loginId != null) return false; } else if (!loginId.equals(other.loginId)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; return true; }