论坛首页 入门技术论坛

Hibernate Bean的Equals方法重载问题

浏览 15518 次
该帖已经被评为新手帖
作者 正文
   发表时间:2009-05-29   最后修改:2009-05-29
啊,楼主至少还要再次修改两个id的用法,id都换成getId()。
0 请登录后投票
   发表时间:2009-05-30   最后修改:2009-05-30
这个问题有意思,不应该被投新手帖的呀,这个问题并不是大家所想的那样,还要从Cglib的内部机制和java调试JDA两方面造成的。我来说说真正的原因吧。
0 请登录后投票
   发表时间:2009-05-30   最后修改:2009-05-30
首先,我们看看这句:

System.out.println("LOC_3 : "  + token == taskInstance.getFlowToken());  

这说明token 和taskInstance.getFlowToken()  得到的是同一个对象,都是Cglib的代理类。

那么在这过程中有几个类呢?

第一有FlowToken  和 FlowToken$Proxy类(Cglib创建的),而token是FlowToken$Proxy的实例。

那么Cglib怎么实现代理的呢?它并不会修改原类的任何部分,只会新创建一个类,复写所有父类的public方法

那么在FlowToken$Proxy里面equels就变成:

public  boolean  equels(Object obj){

	doCglibHandle...

	super.equels(obj);


	doCglibHandle...

}


而,这里最要注意的是在调试工具里面设置的断点一直都是FlowToken该方法的某一行,而不是FlowToken$Proxy类里面的,(这点你可以在debug时注意看stack,可以看到先被FlowToken$Proxy.equels调了以后才到你的断点),所以,你监控的是父类

再看父类的方法:

public boolean equals(Object obj) {   
    if (this == obj)   
        return true;   
    if (obj == null)   
        return false;   
    if (!(obj instanceof FlowToken))   
        return false;   
    final FlowToken other = (FlowToken) obj;   
    if (id == null || other.id == null) {   
        return false;   
    } else if (!id.equals(other.id))   
        return false;   
    return true;   
}  



第一行,为什么不等呢?很简单,这里的this已经是父类的实例,而不是你的token ,所以和传进来的实例自然不等。

那么为什么你看到的传进来的Obj属性全是null,也很简单,因为这个obj也是hibernate的代理出来的一个延时加载类,所有属性都没有的,都是通过get从数据库获得。

不知,这样解释,LZ明白否?

0 请登录后投票
   发表时间:2009-05-30  
icewubin 写道
给所有人建议,hibernate中取ID有更好的通用方法,明天我来贴代码,可以放在BaseModel中的。

http://www.iteye.com/topic/397854
0 请登录后投票
   发表时间:2009-05-31  
leadyu 写道
首先,我们看看这句:

System.out.println("LOC_3 : "  + token == taskInstance.getFlowToken());  

这说明token 和taskInstance.getFlowToken()  得到的是同一个对象,都是Cglib的代理类。

那么在这过程中有几个类呢?

第一有FlowToken  和 FlowToken$Proxy类(Cglib创建的),而token是FlowToken$Proxy的实例。

那么Cglib怎么实现代理的呢?它并不会修改原类的任何部分,只会新创建一个类,复写所有父类的public方法

那么在FlowToken$Proxy里面equels就变成:

public  boolean  equels(Object obj){

	doCglibHandle...

	super.equels(obj);


	doCglibHandle...

}


而,这里最要注意的是在调试工具里面设置的断点一直都是FlowToken该方法的某一行,而不是FlowToken$Proxy类里面的,(这点你可以在debug时注意看stack,可以看到先被FlowToken$Proxy.equels调了以后才到你的断点),所以,你监控的是父类

再看父类的方法:

public boolean equals(Object obj) {   
    if (this == obj)   
        return true;   
    if (obj == null)   
        return false;   
    if (!(obj instanceof FlowToken))   
        return false;   
    final FlowToken other = (FlowToken) obj;   
    if (id == null || other.id == null) {   
        return false;   
    } else if (!id.equals(other.id))   
        return false;   
    return true;   
}  



第一行,为什么不等呢?很简单,这里的this已经是父类的实例,而不是你的token ,所以和传进来的实例自然不等。

那么为什么你看到的传进来的Obj属性全是null,也很简单,因为这个obj也是hibernate的代理出来的一个延时加载类,所有属性都没有的,都是通过get从数据库获得。

不知,这样解释,LZ明白否?




难得有人把事情说清楚了,这样即使被评新手,也认了。

JE上浅薄的人不少啊,还有不少人吧思路放在equals方法的逻辑上,又或者简单的说明proxy中那些谁都明白的概念。
如果问题都那么简单,还用发贴?!
这种问题别不见的人人都碰到并及时发现的。发贴更多是想提醒大家,碰到同样问题的时候,可以很快的醒悟,但很多人在BBS上只是想显摆自己很牛...
动不动就是隐藏和新手,我看je这样走不远(一直希望它能超越CSDN,看来是很困难了)
0 请登录后投票
   发表时间:2009-05-31   最后修改:2009-05-31
melode11 写道
你自己的equals逻辑错了。只要你对象的id == null,你就不管两个实际上相不相等,直接return false。
  if (id == null || other.id == null)

应该改成

  if ((id == null || other.id == null) &&!(id ==null&&other.id==null))


你这种逻辑根本不是我要的,对我而言要的业务逻辑是就当id为空时,对象相等比较是无意义的,应设置为不相等。
而且你的写法根本解决不了我提的问题。

不要动不动就说人家的逻辑错了,你根本不知道我要的equals逻辑是啥,又凭什么说我错呢!!
0 请登录后投票
   发表时间:2009-05-31   最后修改:2009-05-31
要说equals方法逻辑问题,不知道楼主说的哪个部分。

下面这个短路运算就是有问题的,虽然和这贴讨论的东西没有任何关系。
if (!(obj instanceof FlowToken))      
        return false;


深入研究Java equals方法
0 请登录后投票
   发表时间:2009-05-31  
leadyu 写道
首先,我们看看这句:

System.out.println("LOC_3 : "  + token == taskInstance.getFlowToken());  

这说明token 和taskInstance.getFlowToken()  得到的是同一个对象,都是Cglib的代理类。

那么在这过程中有几个类呢?

第一有FlowToken  和 FlowToken$Proxy类(Cglib创建的),而token是FlowToken$Proxy的实例。

那么Cglib怎么实现代理的呢?它并不会修改原类的任何部分,只会新创建一个类,复写所有父类的public方法

那么在FlowToken$Proxy里面equels就变成:

public  boolean  equels(Object obj){

	doCglibHandle...

	super.equels(obj);


	doCglibHandle...

}


而,这里最要注意的是在调试工具里面设置的断点一直都是FlowToken该方法的某一行,而不是FlowToken$Proxy类里面的,(这点你可以在debug时注意看stack,可以看到先被FlowToken$Proxy.equels调了以后才到你的断点),所以,你监控的是父类

再看父类的方法:

public boolean equals(Object obj) {   
    if (this == obj)   
        return true;   
    if (obj == null)   
        return false;   
    if (!(obj instanceof FlowToken))   
        return false;   
    final FlowToken other = (FlowToken) obj;   
    if (id == null || other.id == null) {   
        return false;   
    } else if (!id.equals(other.id))   
        return false;   
    return true;   
}  



第一行,为什么不等呢?很简单,这里的this已经是父类的实例,而不是你的token ,所以和传进来的实例自然不等。

那么为什么你看到的传进来的Obj属性全是null,也很简单,因为这个obj也是hibernate的代理出来的一个延时加载类,所有属性都没有的,都是通过get从数据库获得。

不知,这样解释,LZ明白否?




还有一件事不明白,就是我在跟踪的时候,就像你说的this.id是有值的,但other.getId()依然返回null。
你上面说的,我基本明白了,直接取属性有问题,但通过get方法取id,应该要返回值才是啊?
0 请登录后投票
   发表时间:2009-05-31  
icewubin 写道
要说equals方法逻辑问题,不知道楼主说的哪个部分。

下面这个短路运算就是有问题的,虽然和这贴讨论的东西没有任何关系。
if (!(obj instanceof FlowToken))      
        return false;


深入研究Java equals方法


感谢提供了这么有用的思路。 确实有这个问题。但就性能而言,尤其是在有了类型约束的Set和Map的容器比较中,我还是偏向于旧的,“带有问题”但高性能的实现。当然,会慎重的考虑到文章中提到的bug(如果出现了逻辑上的不正确,特别会去思考一下,是不是这个问题造成的,呵呵)
0 请登录后投票
   发表时间:2009-05-31   最后修改:2009-05-31
linliangyi2007 写道
icewubin 写道
要说equals方法逻辑问题,不知道楼主说的哪个部分。

下面这个短路运算就是有问题的,虽然和这贴讨论的东西没有任何关系。
if (!(obj instanceof FlowToken))      
        return false;


深入研究Java equals方法


感谢提供了这么有用的思路。 确实有这个问题。但就性能而言,尤其是在有了类型约束的Set和Map的容器比较中,我还是偏向于旧的,“带有问题”但高性能的实现。当然,会慎重的考虑到文章中提到的bug(如果出现了逻辑上的不正确,特别会去思考一下,是不是这个问题造成的,呵呵)

用getClass()==getClass()做比较就可以常规短路,这是Eclipse代码生成equals()的实现方法。

如果要支持Hibernate代理对象,可以这样:
        if (getClass().getPackage() != other.getClass().getPackage()) {   
            return false;   
        } 

至于性能高不高,楼主有空可以自己测一下,我也没细测,但是看过JDK源代码,没什么问题,而且都是引用(内存地址)比较,应该不慢。
0 请登录后投票
论坛首页 入门技术版

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