本文共 1710 字,大约阅读时间需要 5 分钟。
在编写Java类的equals和hashCode方法时,选择对象属性是可变的还是不可变的,直接关系到类在集合操作中的行为和性能。这一选择背后有着深厚的技术考量,本文将从原理与实际应用两个层面探讨这一问题。
##Storyboard
###不可变属性的优势
StringBuilder类选择继承Object的hashCode方法,这一选择背后有着深刻的技术原因。实际上,StringBuilder的属性是可变的,它的car次数组可以被修改。然而,它并没有重写hashCode方法。这是为什么呢?通过分析等 Rentals
从理论上讲,当类的属性是可变的时,getHashCode()方法的结果可能会因为属性的变化而变化. 此时, 当该对象被添加到集合中时, 集合记录它的唯一标识符(即hashCode值)也是该值. 如果这个值随着时间的推移发生改变, 根据集合中的存储机制, 操作可能会遇到问题.
例如, 当HashTest类包含可变属性时, 它在被添加到集合之后, 可能会因为可变属性的改变而在集合中位置失准, 导致contains()方法返回false, 虽然对象仍然存在. 这是一个令人不舒服的情况.
这个时候, 为什么String类选择可变属性重写hashCode方法呢?因为String类的属性是final,不能被修改. 这使得其每次调用hashCode方法所产生的值都是一样的,从而保证了性能和一致性.
而StringBuilder继承自Object, 因此其重写当然继承了Object的默认hashCode方法, 这也是为什么它可以保持与其他对象一致性的原因.
###对可变属性的潜在风险在HashTest类的例子中, 可变属性导致的问题已经非常突出. 当集合记录对象的位置是基于初始的hash值计算的, 而当object的可变属性发生改变后, 她们的位置自然会出现偏移. 这是不够的,因为在集合操作中, 记录的位置将与其关联的对象值不再保持同步.
这不是说可变属性不能发挥作用, 而是说它们在equals和hashCode方法中不能随意应用. 只有在满足以下条件时才可以使用可变属性:
事实上, 这种情况的典型表现是未经意中改变对象的identity, 但由于集合中的记录机制并未抓住这点而导致问题发生. 这种现象引人深思.
###性能考量对于一个拥有大量可变属性的类来说, 每次修改属性都会导致两个重要的方面产生影响:
这不仅会导致性能下降,而且也可能导致编写这样的类更加困难. 从另一方面来看, String类因为属性不可变,所以无需为每个修改操作做任何事情. 这始终是一个重要的不争的事实.
从这个角度来说, 在大多数情况下, 可变属性在equals和hashCode方法中的使用都是可以避免的. 只有当你完全确定所有状态的变化都不会引起等价性(equal)的变化时, 才可以依靠它们.
###改进建议为了避免在集合中的行为异常,建议在设计类时尽量避免使用可变属性, 或者在已有类哪里的情况下,明确规定类的状态变化不影响equal和hashcodemic存的计算方式.
因此, my建议是这样:
这些方法论将确保在集合操作中拥有可靠和可预测的行为.
##总结在编写Java类的equals和hashCode方法时,应尽量尽量避免使用可变属性. 如果无法避免, 就必须采用严格的公式化方式来确保一致性和可逆性. 这样不仅能够确保 Collection类别的正确操作,也可以提高整体应用程序的性能和可维护性.
转载地址:http://fwxoz.baihongyu.com/