hibernate中提倡持久类实现equals()和hashCode()的原因分析
2012-09-08 17:12
841 查看
读《Hibernate3.0.2完整中文教程》中的“5.5 实现equals()和hashCode()”一文,在本文中强调,当对于多表关联的数据进行操作时,尤其想把持久类的实例放入Set时(在Hibernate中这种操作尤其常见),或者想重用脱管实例时,均需要对equals()和hashCode()方法进行重写。
原因是由于在Hibernate中,需要保证持久化标识(数据库的行)和仅在特定会话范围内的Java标识是等值的。我们必然希望Set有明确的语义,以避免混合了来自不同会话中获取的实例,从而确保数据的持久化不会发生错误。
若使用过Set,你会知道Set中是不允许存储重复值的,这也是为什么Hibernate推荐在多表关联的映射中采用Set作为存储实体对象的主要原因。在多表关联映射中的持久类中,常见如下代码:
private Set<?> sysUsersRoles = new HashSet(0);
private Set<?> sysRolesAuthorities = new HashSet(0);
public Set getSysUsersRoles() {
return this.sysUsersRoles;
}
public void setSysUsersRoles(Set sysUsersRoles) {
this.sysUsersRoles = sysUsersRoles;
}
public Set getSysRolesAuthorities() {
return this.sysRolesAuthorities;
}
public void setSysRolesAuthorities(Set sysRolesAuthorities) {
this.sysRolesAuthorities = sysRolesAuthorities;
}
按照Hibernate的提倡,应该在该持久化类里,重写equals()和hashCode()方法。那么为什么要对这两个方法进行重写呢? Set里面不是不允许有重复的值吗?
重写这两个方法究竟能起到什么作用?equals()和hashCode()的意义究竟是什么?
这是我看到Hibernate提倡的重写这两个方法之后我的疑问!
不妨先来探讨一下equals()和hashCode()的作用吧。
实际上,equals()和hashCode()这两个方法存在的意义是为了区别对象。这两个方法均来自于Object类。
在对象运行期间,为了在运行期区别各对象,就是通过这两个方法,它们之间的区别如下:
1.Object类的public boolean equals(Object obj)方法是通过 return this == obj;这种方式比较两个对象是否相同。这里比较的是引用。
2.Object类的public int hashCode()方法,是通过该实例地址转换为int值。所以不同的Object实例在同一运行期hashCode一定不相同。
现在解决了equals()和hashCode()是什么以及什么作用的问题。
那么再来谈谈Hibernate的运行机理吧:
在Hibernate的运行期内,通过find或者其他方式提取的对象列表,在不同上下文的操作中,或者在瞬时、持久、脱管三种状态的变换中,为了避免类名相同,但对象内容不同的实例互相碰撞造成混乱,就需要采用更加准确的区别对象的方法,而此时的equals()和hashCode()已经不能满足要求,只有对这两个方法进行重写,增加对这些持久类的各属性的内容进行区分,才能真正区分从Hibernate的find方法中提取的对象。
那么什么样的实例才算是相同的呢? 当然除了你的持久类名标识之外,还需要明确的标识出持久化实例中某些属性的值也是相等的,两个实例才算是真正相同。
比如以下两行数据来自于Person表(字段内容包括ID,姓名name,年龄age,父亲姓名fartherName),这是实例相同的例证:
1,王长江,30,王有才;
1,王长江,30,王有才;
以下两行实例是不相同的例证:
1,王长江,30,王有才;
1,王长江,30,王有财;
哈哈,看出区别来了吗? 只有一字只差,就会在Hibernate管理的实例中被看作两个实例,这就是你重写hashCode()的重要作用。
顺便将重写的hashCode()和equals()也写在下面吧:
public boolean equals( Object other ){
if( this == other ) return true;
if( !( other instanceof Person ) ) return false;
final Person person = (Person)other;
if( !person.getName().equals( getName() ) ) return false;
if( !person.getAge().equals( getAge())) return false;
if( !person.getFartherName().equals( getFartherName())) return false;
return true;
}
public int hashCode(){
int result;
result = getName().hashCode();
result = 29 * result + getAge();
result = 29 * result + getFartherName();
return result;
}
还有,朋友们也可以键入以下代码尝试一下两者的区别:
public static void main(String[] args){
SysRoles role1 = new SysRoles("1","lxb","ljh");
SysRoles role2 = new SysRoles("1","lxb","ljh");
/*
* 经过试验,当不重写equals和hashCode时显示为false;
* 重写时,显示为true。
* 这就是为什么重写equals和hashCode的原因,当你希望从hiberate中提取的对象实例中,
* 若是所有字段的内容都相同,就认为这两个对象实例是相同的,此时就需要重写equals和hashCode。
* 重写equals和hashCode意味着,混杂在不同上下文及Session中的两个实例对象有了确定的语义。
*/
System.out.println(role1.equals(role2));
/*
* 经过试验,当不重写equals和hashCode时显示为false;
* 重写时,显示为true。
*
*/
System.out.println(role1.hashCode() == role2.hashCode());
}
原因是由于在Hibernate中,需要保证持久化标识(数据库的行)和仅在特定会话范围内的Java标识是等值的。我们必然希望Set有明确的语义,以避免混合了来自不同会话中获取的实例,从而确保数据的持久化不会发生错误。
若使用过Set,你会知道Set中是不允许存储重复值的,这也是为什么Hibernate推荐在多表关联的映射中采用Set作为存储实体对象的主要原因。在多表关联映射中的持久类中,常见如下代码:
private Set<?> sysUsersRoles = new HashSet(0);
private Set<?> sysRolesAuthorities = new HashSet(0);
public Set getSysUsersRoles() {
return this.sysUsersRoles;
}
public void setSysUsersRoles(Set sysUsersRoles) {
this.sysUsersRoles = sysUsersRoles;
}
public Set getSysRolesAuthorities() {
return this.sysRolesAuthorities;
}
public void setSysRolesAuthorities(Set sysRolesAuthorities) {
this.sysRolesAuthorities = sysRolesAuthorities;
}
按照Hibernate的提倡,应该在该持久化类里,重写equals()和hashCode()方法。那么为什么要对这两个方法进行重写呢? Set里面不是不允许有重复的值吗?
重写这两个方法究竟能起到什么作用?equals()和hashCode()的意义究竟是什么?
这是我看到Hibernate提倡的重写这两个方法之后我的疑问!
不妨先来探讨一下equals()和hashCode()的作用吧。
实际上,equals()和hashCode()这两个方法存在的意义是为了区别对象。这两个方法均来自于Object类。
在对象运行期间,为了在运行期区别各对象,就是通过这两个方法,它们之间的区别如下:
1.Object类的public boolean equals(Object obj)方法是通过 return this == obj;这种方式比较两个对象是否相同。这里比较的是引用。
2.Object类的public int hashCode()方法,是通过该实例地址转换为int值。所以不同的Object实例在同一运行期hashCode一定不相同。
现在解决了equals()和hashCode()是什么以及什么作用的问题。
那么再来谈谈Hibernate的运行机理吧:
在Hibernate的运行期内,通过find或者其他方式提取的对象列表,在不同上下文的操作中,或者在瞬时、持久、脱管三种状态的变换中,为了避免类名相同,但对象内容不同的实例互相碰撞造成混乱,就需要采用更加准确的区别对象的方法,而此时的equals()和hashCode()已经不能满足要求,只有对这两个方法进行重写,增加对这些持久类的各属性的内容进行区分,才能真正区分从Hibernate的find方法中提取的对象。
那么什么样的实例才算是相同的呢? 当然除了你的持久类名标识之外,还需要明确的标识出持久化实例中某些属性的值也是相等的,两个实例才算是真正相同。
比如以下两行数据来自于Person表(字段内容包括ID,姓名name,年龄age,父亲姓名fartherName),这是实例相同的例证:
1,王长江,30,王有才;
1,王长江,30,王有才;
以下两行实例是不相同的例证:
1,王长江,30,王有才;
1,王长江,30,王有财;
哈哈,看出区别来了吗? 只有一字只差,就会在Hibernate管理的实例中被看作两个实例,这就是你重写hashCode()的重要作用。
顺便将重写的hashCode()和equals()也写在下面吧:
public boolean equals( Object other ){
if( this == other ) return true;
if( !( other instanceof Person ) ) return false;
final Person person = (Person)other;
if( !person.getName().equals( getName() ) ) return false;
if( !person.getAge().equals( getAge())) return false;
if( !person.getFartherName().equals( getFartherName())) return false;
return true;
}
public int hashCode(){
int result;
result = getName().hashCode();
result = 29 * result + getAge();
result = 29 * result + getFartherName();
return result;
}
还有,朋友们也可以键入以下代码尝试一下两者的区别:
public static void main(String[] args){
SysRoles role1 = new SysRoles("1","lxb","ljh");
SysRoles role2 = new SysRoles("1","lxb","ljh");
/*
* 经过试验,当不重写equals和hashCode时显示为false;
* 重写时,显示为true。
* 这就是为什么重写equals和hashCode的原因,当你希望从hiberate中提取的对象实例中,
* 若是所有字段的内容都相同,就认为这两个对象实例是相同的,此时就需要重写equals和hashCode。
* 重写equals和hashCode意味着,混杂在不同上下文及Session中的两个实例对象有了确定的语义。
*/
System.out.println(role1.equals(role2));
/*
* 经过试验,当不重写equals和hashCode时显示为false;
* 重写时,显示为true。
*
*/
System.out.println(role1.hashCode() == role2.hashCode());
}
相关文章推荐
- hibernate中提倡持久类实现equals()和hashCode()的原因分析
- hibernate中提倡持久类实现equals()和hashCode()的原因分析
- hibernate中提倡持久类实现equals()和hashCode()的原因分析
- hibernate中提倡持久类实现equals()和hashCode()分析
- hibernate 五 hibernate 中提倡持久类实现equals()和hashCode()的原因分析
- ID的生成策略(hibernate的id生成策略,主键类为什么需要实现序列化接口,同时还要重写hashCode()和equals()方法)
- hibernate实体实现hashcode与equals方法
- ID的生成策略(hibernate的id生成策略,主键类为什么需要实现序列化接口,同时还要重写hashCode()和equals()方法)
- hibernate之什么时候必须实现equals()和hashCode()方法?
- 为什么Hibernate建议你的实体类实现hashCode和equals方法?
- 重写hashcode和equals的原因探究
- Hibernate入门17 - 实作equals和hashCode
- java中的==、equals()、hashCode()源码分析
- HashMap与HashCode()、equals()的关系---在HashMap中实现以对象为键(key)
- equals和hashCode关系分析
- Java中==、equals()和hashCode()的比较分析
- 详解重写equals()方法就必须重写hashCode()方法的原因
- ArrayList 与HashSet的比较,及应用反射读取properties配置文件中的数据进行实例化再调用,以及类加载器的使用;还有HashCode的分析,及导致内存泄露,内存溢出的原因之一
- 利用asio实现了一个服务器,多个客户端连接,并异常断开连接,发现后面再也连接不上服务器了,不能建立新连接了。原因分析
- hibernate中的po类为什么要重写equals和hashcode方法的对话