该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-05-29
最后修改:2009-05-29
啊,楼主至少还要再次修改两个id的用法,id都换成getId()。
|
|
返回顶楼 | |
发表时间:2009-05-30
最后修改:2009-05-30
这个问题有意思,不应该被投新手帖的呀,这个问题并不是大家所想的那样,还要从Cglib的内部机制和java调试JDA两方面造成的。我来说说真正的原因吧。
|
|
返回顶楼 | |
发表时间: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明白否? |
|
返回顶楼 | |
发表时间:2009-05-30
|
|
返回顶楼 | |
发表时间: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,看来是很困难了) |
|
返回顶楼 | |
发表时间: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逻辑是啥,又凭什么说我错呢!! |
|
返回顶楼 | |
发表时间:2009-05-31
最后修改:2009-05-31
要说equals方法逻辑问题,不知道楼主说的哪个部分。
下面这个短路运算就是有问题的,虽然和这贴讨论的东西没有任何关系。 if (!(obj instanceof FlowToken)) return false; 深入研究Java equals方法 |
|
返回顶楼 | |
发表时间: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,应该要返回值才是啊? |
|
返回顶楼 | |
发表时间:2009-05-31
icewubin 写道 要说equals方法逻辑问题,不知道楼主说的哪个部分。
下面这个短路运算就是有问题的,虽然和这贴讨论的东西没有任何关系。 if (!(obj instanceof FlowToken)) return false; 深入研究Java equals方法 感谢提供了这么有用的思路。 确实有这个问题。但就性能而言,尤其是在有了类型约束的Set和Map的容器比较中,我还是偏向于旧的,“带有问题”但高性能的实现。当然,会慎重的考虑到文章中提到的bug(如果出现了逻辑上的不正确,特别会去思考一下,是不是这个问题造成的,呵呵) |
|
返回顶楼 | |
发表时间: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源代码,没什么问题,而且都是引用(内存地址)比较,应该不慢。 |
|
返回顶楼 | |