JPA实体违反hashCode契约时为何List.contains()仍返回true
问题核心原因可以分为两点:
ArrayList的contains方法完全不依赖hashCode计算ArrayList是线性存储结构,它的contains底层实现是遍历列表内所有元素,逐一调用equals方法和目标对象对比,整个逻辑没有用到对象的hashCode值。只有HashSet、HashMap这类基于哈希表实现的集合才需要遵守「equals相等的对象hashCode必须相等」的契约,普通线性集合不受哈希契约约束,所以哪怕Review对象的hashCode变了也不会影响判断结果。自定义的
equals规则刚好匹配当前场景的判断条件
你编写的Review.equals方法的判断逻辑是:只要两个Review对象的id值相等就返回true,不要求是同一个内存对象:
- 原有
r对象在调用em.persist(r)后,JPA已经为它赋值了生成的主键id=1 - 后续新EntityManager查询出来的
reviews列表里的Review对象,对应数据库记录的id也为1
因此r.equals(reviews.get(0))返回true,contains方法自然返回true。
补充验证:如果你把
Book的reviews字段的实现换成HashSet,就会出现预期的「违反哈希契约导致contains返回false」的问题,因为HashSet会先根据目标对象的当前hashCode找对应的存储桶,对象存入HashSet后hashCode发生变化,就找不到原来的存储桶,直接返回false。
内容的提问来源于stack exchange,提问作者milanHrabos
相关产品推荐
相关产品推荐

