热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

有关对象hashCode可变的疑问

最近,在hibernate中使用JPA注解方式配置bean遇到联合主键时采用@EmbeddedIdprivateBeanPKid;再顶一个BeanPK对象@Embedd
最近,在hibernate中使用JPA注解方式配置bean
遇到联合主键时采用
@EmbeddedId
private BeanPK id;

再顶一个 BeanPK 对象
@Embeddable
public class BeanPK implements Serializable{}

看文档中,要求@Embeddable的BeanPK需要重写hashCode、equals方法;
equals好说;
但hashCode问题就来了
就我所知 java中的hashCode是根据对象的内存地址计算得到的;
String特殊一些,根据字符串内容计算得到的;而String常出现在常量池中。
这样java可以保证每个对象的hashCode是一个固定值。

而我重写BeanPK中的hashCode方法,只能根据BeanPK中的属性的hashCode计算而出。
这样一旦BeanPK中的某个属性改变(例如:调用BeanPK.setXXXX()方法)后 hashCode的值就会改变。

这样就会带来几个问题:
1.当BeanPK放入到集合中
  由于对象存放到集合中的位置依赖对象的hashCode值。
  那么,当对象放入集合后,再改变hashCode的值,集合就找不到该对象了。
  Set中也就无法过滤重复对象。
例子:
  BeanPK pk = new BeanPK("id","name");
  Bean b = new Bean(pk,"age");
  Map map = new HashMap();
  map.put(pk,b);
  pk.setName("newName");//BeanPK 的hashCode会根据id和name计算,setName后hashCode改变
  map.get(pk);//由于hashCode改变,Map已经找不到匹配的key了,这里返回null


2.由于@Embeddable要求实现Serializable
  那么当反序列后,hashCode不一致会不会带来同样的问题?

希望高手指定一下,
另外:在使用@Embeddable时,需不需要重写hashCode方法?

8 个解决方案

#1


我刚刚大二 我说说我对于hashcode的比较浅显的理解。我前段时间也有同样的疑问。后来我查了查。
set是要求无序不重复的 而要保证添加进去的每个对象都是不重复的那么只能重写该对象的equals和hashcode方法。在添加的时候就已经改变了hashcode。

也许文不对题 但我就是这样去记住使用的 期待大神的解答。

#2


大二就这么厉害了。。。。。

hashCode不一定是根据内存得到的。string对象的hashCode,就是每个字符乘以31的次方作为分别的权重计算得到的。你可以看下源码。实际上hash函数的设计本来就很复杂。像你这种情况要避免变动的成员用来计算hashCode。

不过内容变了对象本来就不是同一个了吧。。比如你这个对象,性别变成女了。。还是你自己么。。

#3


Map的key要求是一个不可变的值对象。可变的不应该作为key。

#4


引用 3 楼 huntor 的回复:
Map的key要求是一个不可变的值对象。可变的不应该作为key。

那么 在JPA 文档中对于联合主键@EmbeddedId 大多都说要 重写 hashcode。
那么作为 实体识别 的 @EmbeddedId 能否做key呢!?

#5


引用 2 楼 mingzidaodiduochang 的回复:
大二就这么厉害了。。。。。

hashCode不一定是根据内存得到的。string对象的hashCode,就是每个字符乘以31的次方作为分别的权重计算得到的。你可以看下源码。实际上hash函数的设计本来就很复杂。像你这种情况要避免变动的成员用来计算hashCode。

不过内容变了对象本来就不是同一个了吧。。比如你这个对象,性别变成女了。。还是你自己么。。

……



就我所知 java中的hashCode是根据对象的内存地址计算得到的;
String特殊一些,根据字符串内容计算得到的;而String常出现在常量池中。


常规设计的时候,当页面需要批量添加Bean实体时
Action 通常 会传递一个 List 或者 Map 进入Service层
但在Action层中 BeanPK中的 id 还没生成,可能需要到Service层或者Dao层时才分配id

那么在设计的时候 是否应该在 Action 和 Service 以及Dao 层中传递不同的集合?
(也就是说 从Action 开始传递的那个集合 到Service 或者 Dao 层 可能由于BeanPK的hashcode改变 而造成 get() 是一个null)
在设计中如何避免此类问题,
我的印象中 除了 String 以及 基本类型的包装类 以外 基本上都是使用 Object的hashcode方法
而 Object的hashcode 是使用 JNI 方式 直接使用内存地址 计算得出的hashcode

既然如此,是否可在设计时 @EmbeddedId 的对象 不重写hashcode方法,只重写equals方法???

#6


引用 5 楼 qiuyufeifei 的回复:
引用 2 楼 mingzidaodiduochang 的回复:大二就这么厉害了。。。。。

hashCode不一定是根据内存得到的。string对象的hashCode,就是每个字符乘以31的次方作为分别的权重计算得到的。你可以看下源码。实际上hash函数的设计本来就很复杂。像你这种情况要避免变动的成员用来计算hashCode。

不过内容变了对象本来就不是同一个了……


String 是immutable的类,所以不存在你说的问题,另外 String 的 hashCode 实现比较特殊,可以叫“lazy hashcode”,不建议模仿。

"既然如此,是否可在设计时 @EmbeddedId 的对象 不重写hashcode方法,只重写equals方法??? "
那么你的equals方法又要依据什么来判断呢?
只重写equals方法通常是不对的。因为可能出现两个对象 equals 为 true,而hashCode却不相等的情况,这与HashMap和HashSet是一定不兼容的。

“Action 通常 会传递一个 List 或者 Map 进入Service层
但在Action层中 BeanPK中的 id 还没生成,可能需要到Service层或者Dao层时才分配id”

这句话听起来就是有问题的,"BeanPK中的 id 还没生成",如果BeanPK是依赖id来比较equals,那id应该满足以下条件:

1 - 在构造方法中就已经安全的赋值
2 - 在对象构造以后不能再改变

简单的说,就是 final + immutable(或primitive)
用于hashCode的成员也一样要满足以上条件。

换句话说,如果BeanPK中的id不满足以上条件,那id不应该用作equals和hashCode的依据。

#7


引用 6 楼 raistlic 的回复:
引用 5 楼 qiuyufeifei 的回复:引用 2 楼 mingzidaodiduochang 的回复:大二就这么厉害了。。。。。

hashCode不一定是根据内存得到的。string对象的hashCode,就是每个字符乘以31的次方作为分别的权重计算得到的。你可以看下源码。实际上hash函数的设计本来就很复杂。像你这种情况要避免变动的成员用来计算hashCod……


看来 BeanPK中的属性 需要使用 final 才能避免一些问题。
但这里还有一个问题,
由于 我使用hibernate,当hibernate从数据库中取出对象后,貌似实例对象时使用的是对象的无参构造器,然后调用 set方法
那么 hibernate 会不会调用 BeanPK() 然后再 setId(String id) 呢!!???
如果hibernate按照上述步骤实例,那么 id 设置成final就不行咯! 

#8


引用 7 楼 qiuyufeifei 的回复:
引用 6 楼 raistlic 的回复:引用 5 楼 qiuyufeifei 的回复:引用 2 楼 mingzidaodiduochang 的回复:大二就这么厉害了。。。。。

hashCode不一定是根据内存得到的。string对象的hashCode,就是每个字符乘以31的次方作为分别的权重计算得到的。你可以看下源码。实际上hash函数的设计本来就很复杂。像你这种情……


上面说的情况比较严格,说的是安全的 hash key 应该满足的,——按这个标准所有的 JavaBean 大概都不满足条件(或者只能用默认的 equals 和 hashCode)……

——事实上只要保证:

当一个对象作为 key 被加进 HashMap 或者 HashSet 以后,使用 HashMap 和 HashSet 期间,这个对象的 equals 和 hashCode 不发生变化就行了。

推荐阅读
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 在 Flutter 开发过程中,开发者经常会遇到 Widget 构造函数中的可选参数 Key。对于初学者来说,理解 Key 的作用和使用场景可能是一个挑战。本文将详细探讨 Key 的概念及其应用场景,并通过实例帮助你更好地掌握这一重要工具。 ... [详细]
  • 本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • HBase运维工具全解析
    本文深入探讨了HBase常用的运维工具,详细介绍了每种工具的功能、使用场景及操作示例。对于HBase的开发人员和运维工程师来说,这些工具是日常管理和故障排查的重要手段。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本文详细介绍了 Java 中 org.geotools.data.shapefile.ShapefileDataStore 类的 getCurrentTypeName() 方法,并提供了多个代码示例,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 本文探讨了在Java中实现系统托盘最小化的两种方法:使用SWT库和JDK6自带的功能。通过这两种方式,开发者可以创建跨平台的应用程序,使窗口能够最小化到系统托盘,并提供丰富的交互功能。 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
author-avatar
再见看淡_266
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有