覆盖equals方法看似很简单,可是有许多覆盖方法或致使错误,避免这些错误最直接的方法就是不覆盖equals。
至于何时不覆盖equals方法,主要有下面三种:
1:类的每一个实例本质上是惟一的。
对于代码活动实体而不是值的类,如Thread,Object提供的equals实现就是这些类的行为
2:不关心类是否提供了“逻辑相等”的测试功能
如Random类提供了随机数产生的能力,Object继承过来的equals已经足够了
3:超类已经覆盖了equals,从超类继承过来的行为对于子类也是适合的
如Set实现都是从AbstractSet继承equals实现,List实现从AbstractList继承equals实现,Map实现从AbstractMap继承equals实现。
4:类是私有的或者包级私有,能够肯定它的equals方法用于不会被调用。不过为了以防被意外调用,最好仍是覆盖下equals
@Override
public boolean equals(Object o){
throw new AssertionError();
}数组
那何时应该覆盖equals方法呢?
若是类具备本身特有的“逻辑相等”(不一样意对象同等),并且超类没有覆盖equals来实现指望的行为,这时候就须要覆盖equals方法了。一般这种类是“值类”,仅仅表示值的类,如Integer,Date,在利用equals方法时比较对象引用时,但愿知道它们在逻辑上是否相等(值是否相等),而不是它们是否指向同一个对象。这不只必须覆盖equals方法,还可让这个类的实例能够被用做映射表map中的key值或set中的元素。一种特殊的“值类”,实例受控确保“每一个值至多只存在一个对象”的类,如枚举类型,对应这样的类,逻辑等同域对象等同是一样的,所以Object提供的equals以知足,就无需覆盖。
dom
在覆盖equals时,必须遵照它的通用约定,约定内容以下:
1:自反性,对于任何非null的引用值x,x.equals(x)必须返回true
2:对称性,对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
3:传递性:对于任何非null的引用值x、y和z,若是x.equals(y)返回true,而且y.equals(z)返回true,那么x.equals(z)也必须返回true。
4:一致性:对于任何非null的引用值x和y,只要equals的比较操做在对象中所用信息没有被修改,那么屡次调用x.equals(y)就会一致地返回true或一致地返回false。
对于任何非null的引用值x,x.equals(null)必须返回false。ide
实现高质量equals方法的诀窍:
1:用==操做符来检查“参数是不是这个对象的引用”。若是是,则返回true。这样作是为了提升性能。
2:使用instanceof操做符来检查“参数是否为真确类型”。若是不是,则返回false。“正确类型”通常指的是equals方法所在的类。有些状况是指该类所实现的某个接口。
3:把参数转化为真确的类型。在被instanceof检测事后,咱们就将Object强行转换成上面所提到的“正确的类型”,instanceof保证了咱们转换的真确性。
4:对于该类中的每一个关键域(字段),检查参数中的域是否与该对象中所对应的域相匹配。强转以后,就能够开始匹配两个对象中的字段了。若是匹配成功就能够返回true,
若是“正确的类型”是一个接口,那么须要接口提供方法来访问这些字段,若是是个类的话,那就不用说了。字段匹配技巧:
a、若是是非float和double类型的基本数据类型,那么直接使用==符号。
b、若是是float和double,则使用Float.compare和Double.compare方法。
c、其余类型(也就是那些须要new出对象的类)则调用他们自身的equals方法。有些字段可能被容许为空,因此要进行判断,以下:
field == null ? o.field == null : filed.equal(0.field);
d、数组的话须要遍历每个元素进行匹配,匹配的时候参考上面的三条方法。性能
//一个简单例子 @Override public boolean equals(Object obj){ if(obj == this){//引用是不是指向同一个Person对象 return true; }else if(obj != null&&obj instanceof Person){//类型不为空,且为Person类型或子类。 Person p = (Person) obj; if(this.name == null?this.name==p.getName():this.name.equals(p.getName())){ if(this.age==p.getAge() && this.sex==p.getSex()){ return true; } } } return false; } @Override public int hashCode(){ ...... }
覆盖equals方法的时候咱们还须要注意的地方:
1:覆盖equals的时候老是要覆盖hashCode方法。(为何覆盖和怎么覆盖会在下一篇文章讲)
2:不要企图让equals方法过于智能。只是匹配对象的类型和对象中的各个参数的话很容易作到,而且通常不会违反上面提到的规范。若是你过分的去寻求各类等价关系,那么上面的约定将很难遵照。
3:覆盖equals方法的时候请在方法前面加@Override注解。@Override注解能够防止本想覆盖而错写成重载的方法,若是你的目的是覆盖,就使用该注解,这样在你出错的时候,能提示你你写的方法并非一个覆盖的方法。测试