Java重写hashCode()方法有任何性能问题吗?

如果我将覆盖hashCode()方法将降低应用程序的性能。 我在我的应用程序的许多地方重写了这个方法。

是的,如果hashCode方法以错误的方式实现,则会降低散列集合的性能。 hashCode方法的最佳实现应该为唯一对象生成唯一的hashCode。 唯一的hashCode将避免冲突,并且可以使用O(1)复杂度存储和检索元素。 但是只有hashCode方法无法做到这一点,你需要重写equals方法来帮助JVM。

如果hashCode方法无法为唯一对象生成唯一哈希,那么您有可能在桶中持有多个对象。 当您有两个具有相同哈希的元素但equals方法为它们返回false时,会发生这种情况。 所以每次发生这种情况时,元素都会被添加到散列桶中的列表中。 这将减慢元素的插入和后退。 这将导致get方法的O(n)复杂性,其中n是存储桶中列表的大小。

注意:当您尝试为hashCode实现中的唯一对象生成唯一哈希时,请确保为此执行编写简单算法。 如果用于生成散列的算法太重,那么您在散列集合上的操作肯定会表现不佳。 因为哈希集合上的大多数操作都调用了hashCode方法。

如果在正确的地方使用正确的数据结构,它将提高性能,

例如:Object中的正确哈希码实现几乎可以将O(N)转换为O(1)以进行HashMap查找

除非你在hashCode()方法中做了太多复杂的操作

每次它必须用你的Object处理哈希数据结构时,如果你有重的hashCode()方法(不应该),它会调用hashCode()方法

这完全取决于你如何实现hashCode 。 如果您正在进行大量昂贵的深度操作,那么也许它可能会,并且在这种情况下,您应该考虑缓存hashCode的副本(就像String一样)。 但是一个体面的实现,比如使用HashCodeBuilder ,将不会是一个大问题。 拥有一个好的hashCode值可以使像HashMapHashSet这样的数据结构中的查找更快,更快,如果你重写equals ,你需要覆盖hashCode

Java的hashCode()无论如何都是一个虚函数,因此它被覆盖并使用重写方法这一事实并没有造成性能损失。

真正的区别可能是该方法的实施。 默认情况下, hashCode()工作方式与此类似( 源代码 ):

尽可能合理,Object类定义的hashCode方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但JavaTM编程语言不需要此实现技术。)

因此,只要您的实现如此简单,就不会有性能损失。 但是,如果您基于许多字段执行复杂的计算操作,调用许多其他函数 – 您会注意到性能损失,但仅仅因为您的hashCode()执行了更多操作。

还存在效率低下的hashCode()实现的问题。 例如,如果你的hashCode()只返回值1那么使用HashMapHashSet将比正确实现慢得多。 有一个很好的问题涉及在SO上实现hashCode()equals()的主题: 在Java中覆盖equals和hashCode时应该考虑哪些问题?

还有一点需要注意:记住,每当你实现hashCode()你也应该实现equals() 。 此外,您应该小心谨慎,因为如果您编写无效的hashCode()您可能会破坏各种集合的相等性检查。

在类中重写hashCode()本身不会导致任何性能问题。 但是,当将此类的实例插入到HashMap HashSet或等效数据结构中时,hashCode()和可选的equals()方法将被调用以识别将该元素放入的右桶。同样适用于Retrival Search&Deletion。

由其他人发布的表现完全取决于hashCode()的实现方式。 但是,如果根本不使用特定类的equals方法,则不必重写equals()和hashCode(),但如果重写equals(),则必须重写hashcode()

正如前面提到的所有注释一样,哈希码用于集合中的散列,或者它可以用作equals中的负面条件。 所以,是的,你可以减慢你的应用程序。 显然有更多的用例。

首先,我会说这种方法(是否重写它)取决于你所谈论的对象的类型。

  1. 哈希代码的默认实现尽可能快,因为它对每个对象都是唯一的。 对于许多情况来说,这可能已经足够了。
  2. 当你想要使用hashset时,这并不好,并且假设想要不在集合中存储两个相同的对象。 现在,重点在于“相同”一词。

“相同”可以表示“相同的实例”。 当您的对象是实体时,“相同”可以表示具有相同(数据库)标识符的对象,或者“相同”可以表示具有所有相同属性的对象。 到目前为止它似乎会影响性能。

但是其中一个属性可以是一个可以根据需要评估hashCode()的对象,现在,当你在根对象上调用hash-code方法时,你总能得到对象树的哈希码的评估。

那么,我会推荐什么? 您需要定义并阐明您想要做的事情。 你真的需要区分不同的对象实例,或者标识符是至关重要的,还是它是值对象?

它还取决于不变性。 当使用所有构造函数属性(只有get)构造对象时,可以计算一次hashcode值,并在调用hashcode()时始终使用它。 或者另一种选择是在任何属性发生变化时始终计算哈希码。 您需要确定大多数情况是读取值还是写入它。

我要说的最后一件事是只有当你知道你需要它并且知道你在做什么时才覆盖hashCode()方法。

如果你将覆盖hashCode()方法,它会降低应用程序的性能。如果在正确的位置使用正确的数据结构,它将提高性能,

例如:Object中的正确hashcode()实现几乎可以将O(N)转换为O(1)以进行HashMap查找。无论你在hashCode()方法中做了太多复杂的操作