zoukankan      html  css  js  c++  java
  • 第8条:覆盖equals时请遵守通用约定

    覆盖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以满足,就无需覆盖。

    在覆盖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。

    实现高质量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注解可以防止本想覆盖而错写成重载的方法,如果你的目的是覆盖,就使用该注解,这样在你出错的时候,能提示你你写的方法并不是一个覆盖的方法。

    作者:哀&RT
    出处:博客园哀&RT的技术博客--http://www.cnblogs.com/Tony-Anne/
    您的支持是对博主最大的鼓励,感谢您的认真阅读。
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    【Python之路】特别篇--Python装饰器
    【Python之路】特别篇--Python文件操作
    解决centos7命令行中文乱码
    微信小程序,错误{"errMsg":"request:fail 小程序要求的 TLS 版本必须大于等于 1.2"}
    nodejs 下载远程图片
    屏蔽ps联网激活
    RTMP开发记录 测试服务器搭建篇
    微信公众号文章爬虫抓取实现原理!
    如何更改vs2013中git的远程仓库url地址
    用过企业微信APP 后,微信接收不到消息,解决方案
  • 原文地址:https://www.cnblogs.com/Tony-Anne/p/6726878.html
Copyright © 2011-2022 走看看