为什么需要重载equals?

本文围绕Java实体类重载equals方法展开。以三层结构系统中处理银行信息列表重复数据为例,指出未重载equals时使用ArrayList的contain方法无法过滤重复信息。通过将equals方法重载到BaseValueObject中,利用反射机制对比公共属性和方法,实现简洁代码准确过滤重复信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于实体类中需要重载equals的好处,方法.(JAVA)

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[i].getName();
        if(methodName.startsWith("get")){                    //只处理get方法
          if(methodName.equals("getClass")||
             methods[i].getParameterTypes().length>0){
            continue;
          }
          String tmp=methodName.trim().substring(3);
          flag=(methods[i].invoke(this,null)).equals(methods[i].invoke(obj,null));         //对比取得两个对象的属性值是否相等
        }
      }

      for(int i=0;flag&&i<fields.length;i++){                         
        flag = fields[i].get(this).equals(fields[i].get(obj));                //对比对应的公共属性值是否相等
      }
    } catch(Exception ex){
    }
    return flag;
  }
}


我们的需求达到了,简洁的代码可以很好的工作,因为contain已经可以准确的识别出相同的银行信息了.

为什么我们需要比较公共属性和公共方法,根据约定,如果两个值对象向外展示的属性值相同,我们就认为他们相等
当然,这种应用也只限于这种约定,也就是说我们通过我们外界可以观察到的属性来判断两者是否相等.如果你有不被人知道的私有域,且这种私有域正好成为你识别对象的标志,那这种反射机制是没有帮助的,不过仔细细想想,这样的应用恐怕极少.

好了,如果你有同样的应用和需求,希望我的这些文字能对你有所帮助!
当然任何应用和问题都有特定的领域,有特定的分析,但方法的本身还是很有裨益的.

曹想华 2005/01/03 2005-1-3 15:25:51


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值