【问题标题】:Map and HashCode地图和哈希码
【发布时间】:2013-12-08 06:31:09
【问题描述】:

使基于哈希的集合的唯一 hashCode 工作得更快的原因是什么?以及不使 hashCode 可变的原因是什么?

我读了here,但不明白,所以我阅读了一些其他资源并最终得到了这个问题。

谢谢。

【问题讨论】:

标签: java performance collections hashmap hashcode


【解决方案1】:

哈希码不必是唯一的,但如果不同的对象具有不同的哈希码,它们会更好地工作。

哈希码的一个常见用途是在HashMap 等数据结构中存储和查找对象。这些集合将对象存储在“桶”中,并且所存储对象的哈希码用于确定它存储在哪个桶中。这加快了检索速度。在查找对象时,HashMap 无需遍历所有对象,而是使用哈希码来确定要查找的存储桶,并且只查找该存储桶。

您询问了可变性。我认为您要问的是要求存储在HashMap 中的对象在地图中时不会发生突变,或者最好是该对象是不可变的。原因是,一般来说,改变一个对象会改变它的哈希码。如果一个对象存储在HashMap 中,它的哈希码将用于确定它被存储在哪个桶中。如果该对象发生了变异,它的哈希码就会改变。如果此时查找对象,则会产生不同的哈希码。这可能会将 HashMap 指向错误的存储桶,因此即使该对象之前存储在该 HashMap 中,也可能找不到该对象。

【讨论】:

    【解决方案2】:

    哈希码不需要唯一,它们只是发生冲突的可能性非常低。

    关于哈希码是不可变的,只有当对象将用作HashMap 中的键时才需要。哈希码告诉HashMap 在哪里对桶数组进行初始探测。如果键的哈希码发生变化,则映射将不再在正确的存储桶中查找,并且无法找到条目。

    【讨论】:

      【解决方案3】:

      hashcode() 基本上是一个将对象转换为数字的函数。在基于散列的集合的情况下,此数字用于帮助查找对象。如果这个数字发生变化,这意味着基于散列的集合可能错误地存储了对象,并且无法再检索它。

      哈希值的唯一性允许在集合内部更均匀地分布对象,从而提高性能。如果所有内容都散列到相同的值(最坏的情况),性能可能会下降。

      The wikipedia article on hash tables 提供了一个很好的读物,可能也有助于解释其中的一些内容。

      【讨论】:

        【解决方案4】:

        这与项目在哈希表中的存储方式有关。哈希表将使用元素的哈希码来存储和检索它。在这里完全解释有点复杂,但您可以通过阅读本节了解它:http://www.brpreiss.com/books/opus5/html/page206.html#SECTION009100000000000000000

        【讨论】:

          【解决方案5】:

          为什么通过散列搜索更快?

          假设您有一些独特的对象作为值,并且您有一个 String 作为它们的键。每个键都应该是唯一的,以便在搜索键时,您可以找到它作为其值保存的相关对象。

          现在假设您有 1000 个这样的键值对,您想要搜索特定键并检索其值。如果您没有散列,则需要将您的密钥与表中的所有条目进行比较并查找密钥。

          但是使用散列,您可以散列您的密钥并将相应的对象放入某个桶中以插入。现在,当您要搜索特定键时,将对要搜索的键进行哈希处理并确定其哈希值。您可以直接进入该哈希桶,并选择您的对象,而无需搜索整个关键条目。

          【讨论】:

            【解决方案6】:

            hashCode 是一个棘手的方法。它应该提供平等的简写(这是地图和集合关心的)。如果您的地图中的许多对象共享相同的哈希码,则地图将不得不经常检查equals - 这通常会更昂贵。

            检查equals 的javadoc - 即使对于不可变对象,该方法也很难正确处理,并且使用可变对象作为映射键只是在自找麻烦(因为该对象是为其“旧”哈希码存储的)

            【讨论】:

              【解决方案7】:

              只要您使用的是按索引 (0,1,2...collection.size()-1) 检索元素的集合,就不需要哈希码。但是,如果我们谈论的是像地图这样的关联集合,或者只是询问集合does it contain some elements,那么我们谈论的是昂贵的操作。 哈希码就像提供对象的摘要。它坚固而独特。哈希码通常用于二进制比较。比较每个集合成员的二进制级哈希码并不昂贵,因为通过它的属性比较每个对象(肯定超过 1 个操作)。哈希码需要像指纹一样 - 一个实体 - 一个,并且是不可变的哈希码。

              【讨论】:

                【解决方案8】:

                散列的基本思想是,如果在一个集合中查找一个对象,其散列码与该集合中 99% 的对象的散列码不同,则只需检查散列码匹配的 1% 的对象。如果哈希码与集合中 99.9% 的对象的哈希码不同,则只需检查 0.1% 的对象。在许多情况下,即使一个集合有一百万个对象,一个典型对象的哈希码也只会匹配其中的一小部分(在许多情况下,不到十几个)。因此,单个哈希计算可以消除近百万次比较的需要。

                请注意,哈希值不必绝对唯一,但如果太多实例共享相同的哈希码,性能可能会非常糟糕。请注意,对性能重要的不是不同哈希值的总数,而是它们“聚集”的程度。在包含一百万个事物的集合中搜索一个对象,其中一半的项目都具有一个哈希值,而其余的每个项目都具有不同的值,平均需要检查大约 250,000 个项目。相比之下,如果有 100,000 个不同的哈希值,每个哈希值由 10 个项目返回,那么搜索一个对象将需要检查大约 5 个。

                【讨论】:

                  【解决方案9】:

                  您可以定义一个从 HashMap 扩展的自定义类。然后通过仅使用 equals 方法比较键和值来覆盖方法(get、put、remove、containsKey、containsValue)。然后添加一些构造函数。正确覆盖 hashcode 方法非常困难。

                  我希望我已经帮助了每个想要轻松使用 hashmap 的人。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2021-04-12
                    • 2013-03-21
                    • 1970-01-01
                    • 2017-12-01
                    • 1970-01-01
                    • 2012-09-16
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多