【问题标题】:Why does HashSet preserve insertion order but Set.of does not为什么 HashSet 保留插入顺序但 Set.of 没有
【发布时间】:2021-08-31 16:36:31
【问题描述】:

我有以下代码

public static void main(String[] args) {

    System.out.println("HashSet " + genSet());
    System.out.println("Immutable Set " + genImmutableSet());

}

private static Set<String> genSet() {
    Set<String> set = new HashSet<>();
    set.add("A");
    set.add("B");
    set.add("C");
    set.add("D");

    return set;
}

private static Set<String> genImmutableSet() {
    return Set.of("A", "B", "C", "D");
}

HashSet 的键总是 [A, B, C, D]

Set.of 键有时会被打乱。 我实际上已经多次运行我的代码并得到了我看到的结果。

这是 5 次运行的结果:

Run1:
HashSet [A, B, C, D]
Immutable Set [A, B, C, D]

Run2:
HashSet [A, B, C, D]
Immutable Set [C, D, A, B]

Run3:
HashSet [A, B, C, D]
Immutable Set [A, B, C, D]

Run4:
HashSet [A, B, C, D]
Immutable Set [D, C, B, A]

Run5:
HashSet [A, B, C, D]
Immutable Set [D, C, B, A]

此外,我检查了相关类的实际源代码。

HashSet 依赖于 HashMap 从而使用它的迭代器

HashMap Iterator

Set.of 使用 ImmutableCollections 来实例化它的 Set 并且迭代器可以追溯到here

正如您所看到的,与其他迭代器不同,此迭代器选择基于基于 nano 计算的 SALT 的起始索引,方法如下。

    long nt = System.nanoTime();
    SALT = (int)((nt >>> 32) ^ nt);

我哪里错了?

【问题讨论】:

  • 它实际上并没有保留插入顺序。尝试改变它,你会看到。 Set 不保证订单。不过,有些实现确实有特定的顺序。
  • 我知道 Set 不保证订单。我想知道为什么使用相同的输入会看到不同的输出。

标签: java hash set


【解决方案1】:

原来不同之处在于 Set.of 实际上创建了ImmutableSet

Immutable set 有不同的迭代器,HashSet 迭代器只是像普通列表一样迭代元素,从而保留插入顺序。

另一方面,不可变集合迭代器具有随机起始索引和盐,基于System.nano

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-14
    • 2018-12-10
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    • 2012-12-12
    • 2011-01-23
    • 1970-01-01
    相关资源
    最近更新 更多