首页
论坛
图书
开发资料
在线文档
网址
下载
联系我们
 新闻│Java│JavaScript│Eclipse│Eclipse 英文│J2EE│J2ME│J2SE│JSP│Netbeans│Hibernate│JBuilder│Spring│Struts
站内搜索: 请输入搜索关键词

当前页面: 开发资料首页 → Java 专题 → 为什么需要重载equals?

为什么需要重载equals?

摘要: 为什么需要重载equals?

</td> </tr> <tr> <td height="35" valign="top" class="ArticleTeitle"> <table width="672" border="0"> <tr> <td width="266"> </td> <td width="396">

关于实体类中需要重载equals的好处
Java中的基类Object已经有了equals方法,原型是

public boolean equals(Object obj){
return (this==obj);
}

很明显,比较的标准是对象指针是否相同,也就是说,两个实体类的内部值相同,但内存位置不相同的两个对象按照Object的默认方法是不可能比较相同的,也就是说equals调用将返回false.下面我结合一下遇到的一个问题而产生的想法和解决方案.

该系统是典型的三层结构.Webstart技术做前台-Weblogic应用服务器-Oracle数据库.我们编写的程序很明显的分为两个部分:界面-业务逻辑.关键点是,两者之间交换数据的的类:RequestEvent和ResponseEvent.Event中封装了我们需要传输的数据,我们以用例为单位,每个用例所对应的数据都可以封装成VO,我们称为值对象(value,object).

</td> </tr> </table>

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 boolean addOrNot = true;
YhxxVO yhxxvo = (YhxxVO)yhxxList.get(i);
for(int j=0,count=result.size();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 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 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 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

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

function TempSave(ElementID) { CommentsPersistDiv.setAttribute("CommentContent",document.getElementById(ElementID).value); CommentsPersistDiv.save("CommentXMLStore"); } function Restore(ElementID) { CommentsPersistDiv.load("CommentXMLStore"); document.getElementById(ElementID).value=CommentsPersistDiv.getAttribute("CommentContent"); } </td> </tr> <tr>


↑返回目录
前一篇: 位图排序
后一篇: Java性能优化技巧集锦

首页 | 全站 Sitemap | 联系我们 | 设为首页 | 收藏本站
版权所有 Copyright © 2006-2007, Java 编程资料牛鼻站, All rights reserved