【问题标题】:Weird HashSet behavior with larger values [duplicate]具有较大值的奇怪 HashSet 行为[重复]
【发布时间】:2019-04-15 13:03:46
【问题描述】:

我发现一个(对我来说)在 Java 中实现的 HashSet 的莫名其妙的行为。我像这样实现了 HashSet 并用列表的值填充它。

HashSet<Integer> set = new HashSet<Integer>(list);

我首先使用了一个包含从 0 到 9 的数字的列表来填充 HashSet:

示例:{1,0,5,9,6,7,3,1,3,6,1,5,1,3,4,9,9,7}
输出:[0, 1, 3, 4, 5, 6, 7, 9]

由于 HashSet 通常按升序返回值,直到现在一切正常。但是,一旦我开始使用包含更大值的列表,它就会开始以一种奇怪的方式返回值:

示例:{67,1,122,19,456,42,144,42,3,34,5,5,42}
输出:[1, 34, 67, 3, 5, 456, 42, 144, 19, 122]

我在这里读到了一些关于这取决于内部散列算法的信息:Java HashSet shows list in weird order, always starting with 3,但这更加令人困惑,因为我使用了完全相同的 HashSet,只是具有不同的值。

谁能解释一下为什么会这样?

【问题讨论】:

  • 你为什么担心订单? JavaDoc 说明如下: 它不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。
  • 永远不要依赖HashSet的迭代顺序!
  • @Logan 因为我用它几次来订购整数数组,它适用于较小的值,所以我有点困惑为什么它停止适用于较大的值。不,它不是另一个问题的重复。
  • @Logan 是的,这个回答了。我只是没有找到这个问题。

标签: java list sorting hashset


【解决方案1】:

HashSet 是一个无序的Collection。它不保持插入元素的顺序。所以它不会总是按升序给出值

【讨论】:

  • 它适用于较小的值...
  • @LukasSchröder chrylis 已经给出了为什么它适用于较小值的答案:)
【解决方案2】:

HashSet 明确不提供可预测的排序。

碰巧在第一种情况下,哈希码(Integer 只是整数值)都小于桶数,这意味着如果所有值都低于默认值桶的数量(16),它们会巧合地按顺序排列。

【讨论】:

    【解决方案3】:

    由于 HashSet 通常按升序返回值

    简短的回答,整数 0 到 15,HashSet 恰好是自然顺序。但是,这可能会在未来发生变化,因为这不是一个记录在案的功能,也不是您应该依赖的东西。


    长答案:

    这只是由于密钥的散列方式而发生的。 Integer.hashCode() 实现为

    public int hashCode() {
        return Integer.hashCode(value);
    }
    

    哪个调用

    public static int hashCode(int value) {
        return value;
    }
    

    例如,值 0 到 15 的哈希值只有 0 到 15。

    HashSet 依次获取哈希并对其进行搅拌,以使高位保持有效。

    // from HashMap
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    

    但是,如您所见,在 OpenJDK Java 11 中,0 到 65535 的值没有改变。

    最后,保留低位以确定它们在 HashSet 的数组中的存储位置。

    // from HashMap.putVal
    i = (n - 1) & hash
    

    其中n 是容量,始终是2 的幂。由于默认容量为 16,因此 0 到 15 的值不变。

    此索引i 用于确定应将条目存储在底层数组中的哪个位置。

    当您迭代 HashSet 或 HashMap 时,它只是从数组的第一个索引开始,然后按照索引顺序进行迭代,这也恰好是键的自然顺序。

    【讨论】:

      猜你喜欢
      • 2011-07-27
      • 2012-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-17
      相关资源
      最近更新 更多