论坛首页 Java企业应用论坛

实现实体的hashCode,equals时候请注意

浏览 47739 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-11-23  
id是一个基本类型,怎么可能等于null,代码都好写错了
0 请登录后投票
   发表时间:2004-11-23  
cdliujian 写道
id是一个基本类型,怎么可能等于null,代码都好写错了

偶写的id是Long, 不是基本类型, 怎么不可能等于null, 都好配眼睛了
0 请登录后投票
   发表时间:2004-11-23  
针对一个简单的Users类,由tanghan生成的POJO大概是这样:
package com.adt.po;

import java.io.Serializable;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/** @author Hibernate CodeGenerator */
public class Users implements Serializable {

    /** identifier field */
    private Integer id;

    /** nullable persistent field */
    private String name;

    /** nullable persistent field */
    private String password;
    
    /** full constructor */
    public Users(String name, String password); {
        this.name = name;
        this.password = password;
    }

    /** default constructor */
    public Users(); {
    }

    public Integer getId(); {
        return this.id;
    }

    public void setId(Integer id); {
        this.id = id;
    }

    public String getName(); {
        return this.name;
    }

	public void setName(String name); {
		this.name = name;
	}

    public String getPassword(); {
        return this.password;
    }

	public void setPassword(String password); {
		this.password = password;
	}
	

    public String toString(); {
        return new ToStringBuilder(this);
            .append("id", getId(););
            .toString();;
    }

    public boolean equals(Object other); {
        if ( !(other instanceof Users); ); return false;
        Users castOther = (Users); other;
        return new EqualsBuilder();
            .append(this.getId();, castOther.getId(););
            .isEquals();;
    }

    public int hashCode(); {
        return new HashCodeBuilder();
            .append(getId(););
            .toHashCode();;
    }



}


而我在它生成的基础上,把最后的那三个函数各自append了一个相对稳定的业务字段name。用下来感觉不错啊。为什么大家会对这样一个问题争论不休呢?
0 请登录后投票
   发表时间:2004-11-23  
weihello 写道

两个实体对象其中一个id为null,就不管三七二十一认为两个不相等. 这是什么逻辑?

1,真的很好奇,我认为id为null是否不等,是个业务需求,而在我做的项目中还没有碰见过,真的希望你能举几个现实例子.
2,因为id为null也有可能相等的情况如果存在,会占实体对象多大一部分?如果很少,我会基类全部只比较id,特殊实体再写业务属性对比.
3,在一个集合中,放入具有相同id,但不同类型的实体,这个应用场景我只在缓存的时候碰见过,这时候,一方面,我会采用uuid,如果不能采用uuid,我也会增加一个key的生成规则.
如果说防止开发人员误用第2条,而采取的强制措施,我就不发表意见了,记得有此和人争论:他们为了防止开发人员的null错误,在每个方法开始都要进行输入参数的判断,如果为null,给出详细错误.(虽然觉得有道理,但我是反对派)[/i]
0 请登录后投票
   发表时间:2004-11-23  
youcai, 对于类型的那个,只用一行代码改动就可以避免很多问题的考虑或者莫名其妙的错误,得到更好的语义,我看出来为什么不完善它(当然我不清楚有没有其他的问题),呵呵
0 请登录后投票
   发表时间:2004-11-23  
业务字段不一定就有就有唯一的,不可变的,就像这个论坛的用户信息一样(当然我只是从表面看),说实话,我个人觉得ID本来是最好的。既然这个ID放在实体对象里面,就不代表它仅仅是数据表的主键,而确实是对象自身的标识符。只是由于ID是延迟赋值的,导致这样的矛盾,存在了这样具有奇怪状态的实体。而用业务字段生成hashcode一样会出现HashSet无法重读的现象(当然不会在这样的语义下),只是ID的改变被hibernate隐藏了,不是显式的,所以有点莫名其妙。另外,既然用业务字段来做hashcode之类给我的感觉ID的属性就有点多余了,只是为了迎合关系数据库,象prevayler应该就不需要。

PS 实在不行我可以强制要求所有的entity在new出来之前都保存一次数据库,用工厂创建,当然有点开销,出问题了回滚事务,不知道行不行
0 请登录后投票
   发表时间:2004-11-23  
shenli 写道
youcai, 对于类型的那个,只用一行代码改动就可以避免很多问题的考虑或者莫名其妙的错误,得到更好的语义,我看出来为什么不完善它(当然我不清楚有没有其他的问题),呵呵

一行代码?你是说用利用反射机制的工具类吗?当实体类可以自己包含自己或者many to many时,那有可能导致内存溢出,(我用的是commons_lang的,不知道是不是bug)
我认为更为复杂的实体类是否相同的判断,不是简单的依赖于equals(),相同的对象在不同的场景下,相等的标准不一样,比如用户类,有的关心loginName是否一样,而有的关心电子邮件或者身份证号是否一样.
我个人认为在绝大多数场景下,id足以,因此equals()和hashCode()没必要复杂.真要复杂的,请先举出场景出来.
0 请登录后投票
   发表时间:2004-11-23  
youcai 写道
weihello 写道

两个实体对象其中一个id为null,就不管三七二十一认为两个不相等. 这是什么逻辑?

1,真的很好奇,我认为id为null是否不等,是个业务需求,而在我做的项目中还没有碰见过,真的希望你能举几个现实例子.

  
   “我认为id为null是否不等,是个业务需求”,我不是很明白。呵呵,抱歉。

  实体对象一建立,并非就是来个session.save就了事了。这个实体本身完全可能参与业务计算中。
 
   不止一个人让我举例子了,呵呵,我想看来两位都是习惯新建,然后赋值,接着保存,最后完事了......

    如果实体本身带有行为(不是get,set),这种情况就更加频繁发生了。参考

早前我的TimeRange实现。时间范围这个对象,她本身有交、并、非等等内在行

为。你一新建不可能就直接持久,而是需要和一堆已有的TimeRange交并

非操作后,才最后确定一个实体。

   TimeRange,我说明一下: 时间范围对象(startTime-endTime), 本身提供时间范围的交,并,非服务。

   比如,我一个录像监控有个时间段, 在客户定义的时间段内就启动并开始监控。 如果客户需要增加一个时间段,他只需要提供新增的时间段,然后系统通过交并非等等操作,计算出最后最新需要监控的时间段。

   当然录像监控完全可以不要这么复杂,这里只是一个简单应用的例子。但这个设计是非常有名的,具体出处我给忘了。

   满意否?代码我不写了。
0 请登录后投票
   发表时间:2004-11-23  
youcai 写道
一行代码?你是说用利用反射机制的工具类吗?当实体类可以自己包含自己或者many to many时,那有可能导致内存溢出,(我用的是commons_lang的,不知道是不是bug)


    好像这个帖子的原意就是为了解决你这个问题的。
0 请登录后投票
   发表时间:2004-11-23  
weihello 写道

不止一个人让我举例子了,呵呵,我想看来两位都是习惯新建,然后赋值,接着保存,最后完事了......

如果实体本身带有行为(不是get,set),这种情况就更加频繁发生了。参考

然后赋值, 然后交互, 接着保存, 不就把新的时间区间弄好了么?

你举的这个怎么看也没有说明id为null的object之间的相等比较呀???

另,
TimePoint 和 Duration这种设计的出处在domian driven design这本书的part iii:
http://www.domaindrivendesign.org/articles/blog/evans_eric_sweating_the_small_stuff.html

有一个open source项目就是实现它的:
http://timeandmoney.sourceforge.net/

这种东西在Hibernate里而言, 只是一个UserType, 是一个Entity的属性, 而不会是一个完整的Entity......
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics