TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
关于实体类中需要重载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 |
|