修改对象中引用类型属性为何会导致该对象哈希码变化?
问题分析:修改关联对象属性后,主对象哈希码为何变化?
根本原因
这是完全符合代码逻辑的现象,问题出在Lombok的@EqualsAndHashCode注解的默认行为上:
- 你给
Person和Address都添加了@EqualsAndHashCode,Lombok会自动生成基于类中所有字段的equals()和hashCode()方法。 Person的hashCode()计算逻辑会包含firstName、lastName以及address这三个字段的哈希值。- 当你修改
Address的cityName时,Address自身的hashCode()会因为依赖cityName字段而改变,进而导致Person的hashCode()重新计算后的值也跟着变化。
等价代码验证
Lombok为Person生成的hashCode()逻辑大致等价于下面的代码:
@Override public int hashCode() { return Objects.hash(firstName, lastName, address); }
而Address的hashCode()逻辑是:
@Override public int hashCode() { return Objects.hash(streetName, cityName); }
显然,cityName修改后Address.hashCode()的值改变,代入Person.hashCode()的计算中,最终结果必然发生变化。
关于测试中的浅拷贝
你的测试用了Person.clone(),这是浅拷贝,所以alex和shallowCopyOfAlex指向同一个Address对象。修改alex.getAddress().setCityName()后,两个Person对象的address引用指向的是同一个修改后的Address实例,因此它们的hashCode()会同步变化,这也解释了测试输出里两个Person哈希码前后一致且同时改变的现象。
解决方案:让Person哈希码不依赖Address状态
如果需要Person的哈希码不受Address属性变化的影响,可以修改Person的@EqualsAndHashCode注解,排除address字段:
@Setter @AllArgsConstructor @EqualsAndHashCode(exclude = "address") // 排除address字段 public class Person implements Cloneable { // ... 原有代码内容 }
这样Person的hashCode()只会基于firstName和lastName计算,修改Address的属性就不会影响Person的哈希码了。
内容的提问来源于stack exchange,提问作者Art
相关产品推荐
相关产品推荐

