Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 314|回复: 0

[Java基础知识]为什么需要重载equals?

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-1 07:55:19 | 显示全部楼层 |阅读模式
    关于实体类中需要重载equals的好处
    java中的基类Object已经有了equals方法,原型是 public boolean equals(Object obj){
      return (this==obj);
    }     很明显,比较的标准是对象指针是否相同,也就是说,两个实体类的内部值相同,但内存位置不相同的两个对象按照Object的默认方法是不可能比较相同的,也就是说equals调用将返回false.下面我结合一下遇到的一个问题而产生的想法和解决方案.    该系统是典型的三层结构.Webstart技术做前台-Weblogic应用服务器-Oracle数据库.我们编写的程序很明显的分为两个部分:界面-业务逻辑.关键点是,两者之间交换数据的的类:RequestEvent和ResponseEvent.Event中封装了我们需要传输的数据,我们以用例为单位,每个用例所对应的数据都可以封装成VO,我们称为值对象(value,object).
      
    VO是我们定义的简单的数据封装,有属性,以及对属性的getter和setter方法.实现VO的结构:
    public interface IValueObject extends Serializable{
    }
    public abstract class BaseValueObject Implements IValueObject{ }
         例如我要封装一个银行信息,来作为前后台的交互,信息有银行行别代码(人行,工行,招行...),银行代码,银行名称等.(我们假设就是这三个信息)

    我们定义VO为
    public class YhxxVO extends BaseValueObject{
      private String yhhbdm;
      private String yhdm;
      private String yhmc;

      //getter
      public String getYhhbdm(){
       return yhhbdm;
      }
      ...
      //setter
      public void setYhhbdm(String yhhbdm){
       this.yhhbdm = yhhbdm;
      }
      ...
    }     好,我们通过RequestEvent封装我们查询条件,北京市内所有银行信息.传到后台,后台接受处理,查询数据库,得到一个银行信息列表,在返回的ResponseEvent中,我们取得一个银行信息的列表yhxxList,类型为ArrayList。 由于查找的数据表有其他大量字段或别的原因,导致查询出来的列表可能存在重复信息, 需要把yhxxList中的重复信息过滤掉,放到一个叫做result的列表中.
    大概代码会是这样:(假设没有null空值需要处理) ArrayList result = new ArrayList();
    for(int i=0,size=yhxxList.size();i<size;i++){
      boolean addOrNot = true;
      YhxxVO yhxxvo = (YhxxVO)yhxxList.get(i);
      for(int j=0,count=result.size();j<count;j++){
       YhxxVO resvo = (YhxxVO)result.get(j);
       if(resvo.getYhhbdm().equals(yhxxvo.getYhhbdm())
        && resvo.getYhdm().equals(yhxxvo.getYhdm())
        && resvo.getYhmc().equals(yhxxvo.getYhmc())
       ){
        addOrNot = false;
       }
      }
      if(addOrNot){
       result.add(yhxxvo);
      }
    }      这是一个两重循环,而且两次定义YhxxVO变量,而且内重循环的if判断真够长的,所以严重影响可读性,以至于刚刚接手这段代码的人有点吃不透,比如,有人会提出来result是个空的,内层循环怎么进行等问题.     熟悉ArrayList的程序员可能马上想到,使用ArrayList的contain方法,不就解决了这个不雅观的代码了嘛,是的,很对.
    按照这种想法,我们可以有这样的代码: ArrayList result = new ArrayList();
    for(int i=0,size=yhxxList.size();i<size;i++){
      YhxxVO yhxxvo = (YhxxVO)yhxxList.get(i);
      if(!result.contain(yhxxvo)){
       result.add(yhxxvo);
      }
    } 完了,非常显然,这两段代码的可读性对比异常明显.    可是,事情往往没有那么简单,运行完这段看起来不错的代码后,你会发现result和yhxxList完全一样,并没有把该过滤的重复信息过滤掉,为什么? 因为,contain函数在已有的对象中寻找是否有何参数相同的对象,判断过程的伪码大概是:  在所有的已有对象中循环{
       if(当前对象.equals(参数对象)){
        return true;
       }
      }
      return false; 注意,他调用的是equals,而我们的VO并没有重载equals,所以继承了Object的处理方法:比较指针!
    因此,我们所有的VO都不可能相同.处理方法也变得明显-重载equals.      但是,是不是对我们所有的VO都编写一个equals呢,显然这不是聪明的方法,所谓运筹帷幄,就是修改把equals方法重载到BaseValueObject中去,他所有的子类都可以继承他的equals方法,而不是Object的原始方法.     困难在于,我们VO的判断值相等,却并不知道将来的子类内部都有些什么值.JAVA很精彩的一项功能现身了:反射机制.
    下面是我们处理后的BaseValueObject public abstract class BaseValueObject Implements IValueObject{
       public boolean equals(Object obj){
         if(obj==null){   //参数为空
           return false;
         }     if(this==obj){  //和自己比较
           return true;
         }
         if(!obj.getClass().equals(getClass())){   //传入的不是同一个类型
           return false;
         }     Method[] methods=this.getClass().getMethods();    //取得所有公共方法
         Field[] fields=this.getClass().getFields();                 //取得所有公共属性
         boolean flag=true;                                                     //标志对象是否相等
         try{
           for(int i=0;flag&&i<methods.length;i++){
             String methodName=methods.getName();
             if(methodName.startsWith("get")){                    //只处理get方法
               if(methodName.equals("getClass")||
                  methods.getParameterTypes().length>0){
                 continue;
               }
               String tmp=methodName.trim().substring(3);
               flag=(methods.invoke(this,null)).equals(methods.invoke(obj,null));         //对比取得两个对象的属性值是否相等
             }
           }       for(int i=0;flag&&i<fields.length;i++){                          
             flag = fields.get(this).equals(fields.get(obj));                //对比对应的公共属性值是否相等
           }
         } catch(Exception ex){
         }
         return flag;
       }
    }
    我们的需求达到了,简洁的代码可以很好的工作,因为contain已经可以准确的识别出相同的银行信息了.     为什么我们需要比较公共属性和公共方法,根据约定,如果两个值对象向外展示的属性值相同,我们就认为他们相等
    当然,这种应用也只限于这种约定,也就是说我们通过我们外界可以观察到的属性来判断两者是否相等.如果你有不被人知道的私有域,且这种私有域正好成为你识别对象的标志,那这种反射机制是没有帮助的,不过仔细细想想,这样的应用恐怕极少. 好了,如果你有同样的应用和需求,希望我的这些文字能对你有所帮助!
    当然任何应用和问题都有特定的领域,有特定的分析,但方法的本身还是很有裨益的. 曹想华 2005/01/03 2005-1-3 15:25:51

    本文引用通告地址: http://blog.csdn.net/jiziba/services/trackbacks/238323.aspx
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-2 11:44 , Processed in 0.364758 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表