`
linliangyi2007
  • 浏览: 1012709 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Hibernate Bean的Equals方法重载问题

阅读更多
代码如下:
	
	/**
	 * 判断当前流程实例上下文中,是否存在Blocking(阻挡性)的任务
	 * 规则
	 * 1.任务未结束 
	 * 2.任务是必办理的
	 * 3.当前任务实例的token和执行上下文的token一致
	 * @param token
	 * @return
	 */
	public boolean hasBlockingTaskInstances(FlowToken token) {
		boolean hasBlockingTasks = false;

		System.out.println("LOC_1 :"  + token.getId());

		Set<TaskInstance> taskInstances = flowInstance.getTaskInstances();
		if (taskInstances!=null) {
			Iterator<TaskInstance> iter = taskInstances.iterator();
			
			while ( (iter.hasNext()) && (!hasBlockingTasks)) {

System.out.println("LOC_2 : "  + taskInstance.getFlowToken().getId());
System.out.println("LOC_3 : "  + token == taskInstance.getFlowToken());
System.out.println("LOC_4 : "  + token.equals(taskInstance.getFlowToken());

				TaskInstance taskInstance = (TaskInstance) iter.next();
				if ( (! taskInstance.hasEnded()) //任务未结束 
						&& (taskInstance.getIsBlocking()) //任务是必办理的
						&& (token!=null) 
						&& (token.equals(taskInstance.getFlowToken())) ) {
					hasBlockingTasks = true;
				}
			}
		}
		return hasBlockingTasks;
	}


上述的 LOC_1 处和 LOC_2 处打印的ID完全相等, LOC_3处输出true(说明对象地址相同),BUT~~ LOC_4处输出是false;


给出FlowToken的equals实现
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	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;
	}


跟踪发现,实际进入equals的obj参数根本不是外面传入的那个token对象,中间过程被Hinernate的CGLIBLazyInitializer做了代理处理,发生了底层对象的变换。
开始大家都打死不信有这样的BUG,经过对jvm线程和变量编号的反复跟踪,BUG每次都重现。确认CGLIBLazyInitializer确有问题,但目前在国内互联网上没有找到相同的案例。这里提出,供javaeye上的大牛商讨!

如果我们一群人的诊断是对的,hibernate就隐藏了一个相当恐怖的bug咯!!!
分享到:
评论
36 楼 linliangyi2007 2009-05-27  
icewubin 写道
linliangyi2007 写道
跟踪结果是,同样一句的taskInstance.getFlowToken()在equals方法外取的对象,在java虚拟机的编号和equals方法内部取到的对象根本不一样,换句话中,我们在给equals方法传入参数时,到了equals方法内部的那个对象不是外面传入的那个参数!!!!
很匪夷所思吧~~

你这段话早点表达清楚就不会让很多人绕弯弯了。

你说那个“使用getID也不行”,能把修改过的equals的代码再贴出来看看么?


   1. /* (non-Javadoc) 
   2.  * @see java.lang.Object#equals(java.lang.Object) 
   3.  */  
   4. @Override  
   5. public boolean equals(Object obj) {  
   6.     if (this == obj)  
   7.         return true;  
   8.     if (obj == null)  
   9.         return false;  
  10.     if (!(obj instanceof FlowToken))  
  11.         return false;  
  12.     final FlowToken other = (FlowToken) obj;  
  13.     if (id == null || other.getId() == null) {  
  14.         return false;  
  15.     } else if (!id.equals(other.getId()))  
  16.         return false;  
  17.     return true;  
  18. }  


修改过的equals。这个方法跟踪的时候other.getId() 居然为null,而在equals外,我是能取到这个对象的id的。
35 楼 icewubin 2009-05-27  
linliangyi2007 写道
跟踪结果是,同样一句的taskInstance.getFlowToken()在equals方法外取的对象,在java虚拟机的编号和equals方法内部取到的对象根本不一样,换句话中,我们在给equals方法传入参数时,到了equals方法内部的那个对象不是外面传入的那个参数!!!!
很匪夷所思吧~~

你这段话早点表达清楚就不会让很多人绕弯弯了。

你说那个“使用getID也不行”,能把修改过的equals的代码再贴出来看看么?
34 楼 linliangyi2007 2009-05-27  
KimShen 写道
linliangyi2007 写道
icewubin 写道
虽然我不会投楼主新手帖,但是楼主完全应该在发帖前多测试几下嘛。

这种情况,楼主只要在equals方法中打印几行,几个判断的结果很容易就能发现是哪一个判断返回false。至少到这一步你能知道是other.id不是你预期的结果。


兄弟,你没看贴啊,在发贴前做了完整的跟踪的。你看看原帖的说明吧,而且在equals方法内也做跟踪的,发现对象被替换了。

目前按照楼上的说法,使用getID仍然有问题,还是没有解决!!看来不是方法覆盖那么简单的现象了!


还没有解决?
你跟踪下equals看看


跟踪结果是,同样一句的taskInstance.getFlowToken()在equals方法外取的对象,在java虚拟机的编号和equals方法内部取到的对象根本不一样,换句话中,我们在给equals方法传入参数时,到了equals方法内部的那个对象不是外面传入的那个参数!!!!
很匪夷所思吧~~
33 楼 KimShen 2009-05-27  
linliangyi2007 写道
icewubin 写道
虽然我不会投楼主新手帖,但是楼主完全应该在发帖前多测试几下嘛。

这种情况,楼主只要在equals方法中打印几行,几个判断的结果很容易就能发现是哪一个判断返回false。至少到这一步你能知道是other.id不是你预期的结果。


兄弟,你没看贴啊,在发贴前做了完整的跟踪的。你看看原帖的说明吧,而且在equals方法内也做跟踪的,发现对象被替换了。

目前按照楼上的说法,使用getID仍然有问题,还是没有解决!!看来不是方法覆盖那么简单的现象了!


还没有解决?
你跟踪下equals看看
32 楼 linliangyi2007 2009-05-27  
rrsy23 写道
从这个问题看LZ对java的equlas与hashcode没有理解清楚;
这两个方法是留个自己实现的;

我完全可以写个equals永远返回false,hashcode永远返回一样;

说个实际点的吧;
set 放进去的东西能找到吗?
package com.bobo;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class TestMain {
public static void main(String[] args) {
new TestMain().test1();

}

public void test1() {

Set set = new HashSet();

set.add(new A());
// false
System.out.println(set.contains(new A()));

set.add(new B());
// true
System.out.println(set.contains(new B()));

set.add(new C());
// true
System.out.println(set.contains(new C()));

A a = new A();
set.add(a);
// true
System.out.println(set.contains(a));

B b = new B();
set.add(b);
// true
System.out.println(set.contains(b));

C c = new C();
set.add(c);
// 大部分情况下是false
System.out.println(set.contains(c));

}

class A {

}

class B {

@Override
public int hashCode() {

return 1;
}

@Override
public boolean equals(Object obj) {

return true;
}

}

class C {

@Override
public int hashCode() {
return new Random().nextInt();
}

@Override
public boolean equals(Object obj) {
return true;
}

}

}
理解哈吧,研究哈吧;其实很多书上也讲了;
关键是你思考没有,研究没有;


兄弟们,不要动不动就否定别人不理解hashcode和equals,去看看我的blog吧,本人对java的Set,Map以及相关的equals,hashCode是有相当深入的研究的,如果问题都这么简单,我不会提出来的。

浮躁啊~~je上充满浮躁!!
31 楼 linliangyi2007 2009-05-27  
icewubin 写道
虽然我不会投楼主新手帖,但是楼主完全应该在发帖前多测试几下嘛。

这种情况,楼主只要在equals方法中打印几行,几个判断的结果很容易就能发现是哪一个判断返回false。至少到这一步你能知道是other.id不是你预期的结果。


兄弟,你没看贴啊,在发贴前做了完整的跟踪的。你看看原帖的说明吧,而且在equals方法内也做跟踪的,发现对象被替换了。

目前按照楼上的说法,使用getID仍然有问题,还是没有解决!!看来不是方法覆盖那么简单的现象了!
30 楼 jianfeng008cn 2009-05-27  
谢谢楼上再解释了下,前面有人已经解释过了。
29 楼 linliangyi2007 2009-05-27  
jianfeng008cn 写道
linliangyi2007 写道
jianfeng008cn 写道
KimShen 写道

Test有private Id字段


Test的id应该是public的吧


private 的,因为是在同一个类的内部,所以private可以直接引用



other 不是外面传进去的吗?怎么变成了同个类的内部了?


因为在读取private属性前,other被做了cast操作,强制转成当前对象类型,这时候就允许直接访问对象内部的private属性了,你可以自己写个方法试试,比如,在CLASSA中,有个方法methodA,传入一个参数p1,如果p1 instanceof CLASSA,你就可以将它cast,然后直接读取p1的私有变量了!
28 楼 rrsy23 2009-05-27  
从这个问题看LZ对java的equlas与hashcode没有理解清楚;
这两个方法是留个自己实现的;

我完全可以写个equals永远返回false,hashcode永远返回一样;

说个实际点的吧;
set 放进去的东西能找到吗?
package com.bobo;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class TestMain {
public static void main(String[] args) {
new TestMain().test1();

}

public void test1() {

Set set = new HashSet();

set.add(new A());
// false
System.out.println(set.contains(new A()));

set.add(new B());
// true
System.out.println(set.contains(new B()));

set.add(new C());
// true
System.out.println(set.contains(new C()));

A a = new A();
set.add(a);
// true
System.out.println(set.contains(a));

B b = new B();
set.add(b);
// true
System.out.println(set.contains(b));

C c = new C();
set.add(c);
// 大部分情况下是false
System.out.println(set.contains(c));

}

class A {

}

class B {

@Override
public int hashCode() {

return 1;
}

@Override
public boolean equals(Object obj) {

return true;
}

}

class C {

@Override
public int hashCode() {
return new Random().nextInt();
}

@Override
public boolean equals(Object obj) {
return true;
}

}

}
理解哈吧,研究哈吧;其实很多书上也讲了;
关键是你思考没有,研究没有;
27 楼 rrsy23 2009-05-27  
package com.bobo;

public class TestMain {
public static void main(String[] args) {
new TestMain().test();
}
public void test() {
Parent p = new Son();
// 结果0
System.out.println(p.id);
Son s = (Son) p;
// 结果1
System.out.println(s.id);
/*
* 总结:
* 属性没@Override
* 属性是隐藏,引用是什么类型就调用什么熟悉,方法呵呵大家清楚
*/

}

class Parent {
private int id = 0;

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

}

class Son extends Parent {
// @Override没有这个概念哦
private int id = 1;
@Override
public int getId() {
return this.id;
}
}
}
26 楼 whaosoft 2009-05-27  
icewubin 写道
虽然我不会投楼主新手帖,但是楼主完全应该在发帖前多测试几下嘛。

这种情况,楼主只要在equals方法中打印几行,几个判断的结果很容易就能发现是哪一个判断返回false。至少到这一步你能知道是other.id不是你预期的结果。


首先 赞同

然后 我没积分所以没投了票不好意思
25 楼 icewubin 2009-05-27  
虽然我不会投楼主新手帖,但是楼主完全应该在发帖前多测试几下嘛。

这种情况,楼主只要在equals方法中打印几行,几个判断的结果很容易就能发现是哪一个判断返回false。至少到这一步你能知道是other.id不是你预期的结果。
24 楼 jianfeng008cn 2009-05-27  
这个贴投新手帖很正常啊,要正视自己的水平,我就是新手。不过我自己投了良好~~~
23 楼 liuxuan620 2009-05-27  
jianfeng008cn 写道
linliangyi2007 写道
jianfeng008cn 写道
KimShen 写道

Test有private Id字段


Test的id应该是public的吧


private 的,因为是在同一个类的内部,所以private可以直接引用



other 不是外面传进去的吗?怎么变成了同个类的内部了?

这种情况下,private是没有问题地.
private:除了包含这个成员的类外,其他任何类都无法访问这个成员(说的是类,不是对象)
22 楼 jianfeng008cn 2009-05-27  
linliangyi2007 写道
jianfeng008cn 写道
KimShen 写道

Test有private Id字段


Test的id应该是public的吧


private 的,因为是在同一个类的内部,所以private可以直接引用



other 不是外面传进去的吗?怎么变成了同个类的内部了?
21 楼 zozoh 2009-05-27  
linliangyi2007 写道
靠这也叫新手帖!!
javaeye上有几个新手提这样的问题啊!!
提问题也要有层次好啵?动不动就评新手帖,无语!

嗯,投你一票良好 
20 楼 KimShen 2009-05-27  
我三天两头被新手和隐藏 所以我决定以后不再写任何东西 习惯就好
19 楼 linliangyi2007 2009-05-27  
靠这也叫新手帖!!
javaeye上有几个新手提这样的问题啊!!
提问题也要有层次好啵?动不动就评新手帖,无语!
18 楼 yimlin 2009-05-27  
既然被proxy代理过的,那么目前的状况就正常了。
17 楼 linliangyi2007 2009-05-27  
jianfeng008cn 写道
KimShen 写道

Test有private Id字段


Test的id应该是public的吧


private 的,因为是在同一个类的内部,所以private可以直接引用

相关推荐

    重载equals方法示例

    重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例

    重写equals方法

    例如,public boolean equals(Object o) 是一个正确的重写方法,而 public boolean equals(String o) 是一个重载方法,而不是重写方法。 equals 方法的实现 ------------------------- equals 方法的实现需要遵循...

    equals方法的重写.docx

    ### equals方法重写知识点解析 #### 一、equals方法简介 `equals`方法是Java语言中Object类的一个重要成员方法,其默认实现是比较两个对象的内存地址是否相同(即是否为同一个对象)。为了使对象之间能够基于内容...

    Java中equals方法隐藏的陷阱

    ### Java中equals方法隐藏的陷阱 在Java编程中,正确实现`equals`方法至关重要,它不仅影响对象的比较逻辑,还直接关系到集合类(如`HashSet`、`HashMap`等)的行为。本文将深入探讨Java中`equals`方法的一些常见...

    set接口经常用的hashCode和equals方法详解

    ### set接口中hashCode和equals方法详解 #### 一、引言 在Java编程语言中,`Set`接口作为集合框架的重要组成部分,在实现无重复元素的数据结构方面扮演着关键角色。为了确保元素的唯一性,`Set`接口依赖于对象的`...

    hashcode和equals方法

    equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.

    重写toString和equals方法

    Java 对象的toString和equals方法重写 在 Java 中,每个对象都继承自 Object 类,而 Object 类中定义了两个重要的方法:toString() 和 equals()。这两个方法都是非常重要的,它们分别用于对象的字符串表示和对象...

    js equals方法

    在JavaScript中,`equals`方法并不像在其他某些编程语言中那样是内置的,例如Java。但是,由于JavaScript的灵活性,我们可以自定义一个`equals`函数来实现对象间的深度比较。这个方法通常用于比较两个对象的属性和值...

    tableTobean.rar_CZAF_K7W_TabletoBean_hibernate反向生成bean

    5. 设定生成Bean的模板,可以选择是否生成equals()、hashCode()、toString()等方法,以及字段的访问级别等。 6. 完成设置后,点击“Finish”按钮,开发工具将自动生成对应的Java Bean类和Hibernate映射文件(.hbm....

    Java编程中避免equals方法的隐藏陷阱介绍

    equals方法的四个常见陷阱分别是:定义了错误的equals方法签名,重载了equals的但没有同时重载hashCode的方法,建立在会变化字域上的equals定义,不满足等价关系的equals错误定义。下面将对每个陷阱进行详细的解释...

    java中的==和equals()方法1

    在Java编程语言中,了解如何正确使用`==`和`equals()`方法是非常关键的,因为它们在比较对象和基本类型时有不同的行为。下面将详细解释这两个方法的工作原理、使用场景以及一些常见误区。 首先,`==`运算符主要用于...

    知识点 比较运算符==和equals方法的比较

    在Java编程语言中,比较运算符`==`和`equals()`方法是用来检查两个对象是否相等的,但它们之间存在显著的区别。理解这些差异对于编写正确的代码至关重要。 首先,我们来看`==`运算符。它主要用于基本数据类型的比较...

    java中hashcode()和equals()方法详解

    - 为了避免哈希冲突带来的性能问题,在覆盖`equals()`方法的同时,通常也需要覆盖`hashCode()`方法。 #### 实现示例 以下是一个简单的类`Person`,展示了如何正确覆盖`equals()`和`hashCode()`方法: ```java ...

    2.javaequals()方法.zip

    2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2....

    关于Object中equals方法和hashCode方法判断的分析

    "关于Object中equals方法和hashCode方法判断的分析" 在 Java 中,Object 类提供了两个重要的方法:equals 方法和 hashCode 方法。这两个方法都是用于比较两个对象是否相等的,但它们的实现机理和作用域却有所不同。...

    ==运算符和Equals()方法区别

    字符串是一个特殊的引用类型,在C#语言中,重载了字符串对象的很多方法,包括`Equals()`方法,使字符串对象用起来就像是值类型一样。这也是为什么在上面的例子中,`a`和`b`的比较结果都是`true`的原因。 需要注意的...

    ==和equals方法究竟有什么区别

    在Java编程语言中,`==`和`equals()`方法是用来比较对象之间关系的两种常见方式,但它们在使用上有着显著的区别。 首先,`==`运算符主要用于比较基本类型(如int、char、byte等)的值是否相等,或者比较引用类型...

    C# Equals 和 GetHashCode 方法重写

    ### C# Equals 和 GetHashCode 方法重写 在C#编程中,`Equals` 和 `GetHashCode` 方法是非常重要的成员方法,它们对于确保对象的正确比较以及高效地存储和检索对象至关重要。这两个方法通常需要在自定义类中进行...

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    equals问题经典

    这里我们将深入探讨`equals()`方法的用法,以及它与`==`的区别,同时解决题目中提出的问题。 **问题一:** 在Java中,`String`类的实例有两种创建方式。一种是直接通过字面量,如`String s1 = "abc";`,这时字符串...

Global site tag (gtag.js) - Google Analytics