论坛首页 Java版 Hibernate

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

浏览 27428 次
该帖已经被评为精华帖
作者 正文
最后更新时间:2004-11-18
多对多双向关系,如果hashCode和equals正常写之,将出现load不上的问题。

详情请看
http://www.erproad.org/showlog.asp?cat_id=30&log_id=371
   
最后更新时间:2004-11-18
用得着这么复杂吗?比较一下id不就得了。
[code:1]
public abstract class EntityBase{
  private Long id;
  public Long getId(){
    return id;
  }
  //setter...

  public boolean equals(Object o){
    if(this==o) return true;
    if(o==null) return false;
    if(this.id==null) return false;
    if(getClass!=o.getClass()) return false;
    EntityBase e=(EntityBase)o;
    if(e.id==null) return false;
    return id.equals(e.id);
  }
 
  public int hashCode(){
    return id==null?super.hashCode():id.hashCode();
  }
}
[/code:1]
   
0 请登录后投票
最后更新时间:2004-11-19
比较一下ID就行了吗?

   呵呵,我是不会这样写的。 至于原因,你都想当然了,我也不说了。
   
0 请登录后投票
最后更新时间:2004-11-19
id是不可靠的
如果一个transient po ,id==null
but business value equals existed po,

..........
   
0 请登录后投票
最后更新时间:2004-11-19
winhello,please copy the formatted java source to here .thanks
   
0 请登录后投票
最后更新时间:2004-11-19
zingers 写道
id是不可靠的
如果一个transient po ,id==null
but business value equals existed po,
..........


一个transient object和一个persistent object, 哪怕它们的business value都相同, 偶还是认为它们是不同的

比较ID有什么说不过去的地方呢?偶N个实际项目中就是这样用的......
   
0 请登录后投票
最后更新时间:2004-11-19
比较ID不是太好的方法(当然也是可以)。因为新建PO的时候ID一般都为空或者0.

一般都是用业务字段来比较(复合的业务字段等),例如:像XXXname,或者其它的呀。

不过觉得equals与hashCode并没有很大什么,因为平时我们只是用Set,List,Map等,其实很少有记录重复的。有时我们必须允许重复。

现说PO就是一种数据对象(大部时候只有set/get方法),标识它唯一的是它的ID(或者复合ID)(大部分情况下)。

所以我觉得equals与hashCode并没有多大重要性,甚至可以不override。
   
0 请登录后投票
最后更新时间:2004-11-19
[code:1]
/*
* 作成日: 2004-11-19
*
* この生成されたコメントの挿入されるテンプレートを変更するため
* ウィンドウ > 設定 > Java > コード生成 > コードとコメント
*/

import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* @author Administrator
*
* この生成されたコメントの挿入されるテンプレートを変更するため
* ウィンドウ > 設定 > Java > コード生成 > コードとコメント
*/
public class BasePersistentObject implements Serializable {

public String toString() {
return ToStringBuilder.reflectionToString(
this,
ToStringStyle.MULTI_LINE_STYLE);
}

public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}

Class lhsClass = getClass();
Class rhsClass = o.getClass();
Class testClass;

if (lhsClass.isInstance(o)) {
testClass = lhsClass;
if (!rhsClass.isInstance(this)) {

testClass = rhsClass;

}

} else if (rhsClass.isInstance(this)) {
testClass = rhsClass;
if (!lhsClass.isInstance(o)) {

testClass = lhsClass;

}
} else {
return false;
}

EqualsBuilder equalsBuilder = new EqualsBuilder();
try {
equalsReflectionAppend(o, testClass, equalsBuilder);
while (testClass.getSuperclass() != null
&& !testClass.getSuperclass().equals(Object.class)) {
testClass = testClass.getSuperclass();
equalsReflectionAppend(o, testClass, equalsBuilder);
}
} catch (IllegalArgumentException e) {

return false;
}
return equalsBuilder.isEquals();
}

private void equalsReflectionAppend(
Object rhs,
Class clazz,
EqualsBuilder builder) {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length && builder.isEquals(); i++) {
Field f = fields[i];
if ((f.getName().indexOf('$') == -1)
&& (!Modifier.isTransient(f.getModifiers()))
&& (!Modifier.isStatic(f.getModifiers()))) {
try {
if (Collection.class.isAssignableFrom(f.getType())) {
builder.append(
f.get(this).getClass(),
f.get(rhs).getClass());
} else {
builder.append(f.get(this), f.get(rhs));
}
} catch (IllegalAccessException e) {
//this can't happen. Would get a Security exception instead
//throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
}
}
}

public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder(17, 37);
Class clazz = getClass();
hashCodeReflectionAppend(clazz, builder);
while (clazz.getSuperclass() != null
&& clazz.getSuperclass().equals(Object.class)) {
clazz = clazz.getSuperclass();
hashCodeReflectionAppend(clazz, builder);
}
return builder.toHashCode();
}
private void hashCodeReflectionAppend(
Class clazz,
HashCodeBuilder builder) {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
if ((f.getName().indexOf('$') == -1)
&& (!Modifier.isTransient(f.getModifiers()))
&& (!Modifier.isStatic(f.getModifiers()))) {
try {
if (Collection.class.isAssignableFrom(f.getType())) {
builder.append(f.get(this).getClass());
} else {
builder.append(f.get(this));
}
} catch (IllegalAccessException e) {
//this can't happen. Would get a Security exception instead
//throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
}
}
}

}[/code:1]
   
0 请登录后投票
最后更新时间:2004-11-19
weihello 写道
比较一下ID就行了吗?

   呵呵,我是不会这样写的。 至于原因,你都想当然了,我也不说了。

嘿嘿,你也仔细想想吧
Readonly这回跟我比较一致呀
   
0 请登录后投票
最后更新时间:2004-11-20
Readonly 写道
zingers 写道
id是不可靠的
如果一个transient po ,id==null
but business value equals existed po,
..........


一个transient object和一个persistent object, 哪怕它们的business value都相同, 偶还是认为它们是不同的

比较ID有什么说不过去的地方呢?偶N个实际项目中就是这样用的......


   这个比较ID的超类你不能用于组件类,这是其一. 这个我不多说了.

   继承这个类的类语义不完整,留下隐患,一旦涉及到在hashmap这样的结构中,这个实体就有严重的问题. 其二
(修改:   依照你的意思,实体ID相等就是相等............)

  你要留意你的业务代码中是否采用了equals之类的代码,如果有,他们都是不可靠的. 炸弹不知道什么时候爆炸. 其三.

   懒就是懒,呵呵,我想你该承认.
   
0 请登录后投票
论坛首页 Java版 Hibernate

跳转论坛:
JavaEye推荐