问题描述
对于一些教程,他们说:
HashSet 不保持任何顺序,元素将以任何随机顺序返回。
但是我写了一个测试程序,结果总是一样。
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hs1 = new HashSet<String>();
hs1.add("a");
hs1.add("b");
hs1.add("c");
hs1.add("d");
hs1.add(null);
hs1.add(null);
System.out.println(hs1);
System.out.println(hs1);
}
}
输出:
[null, a, b, c, d]
[null, a, b, c, d]
我试了很多次,但顺序总是一样的。 为什么? 希望有人可以帮助我,在此先感谢!
1楼
这种行为的原因是HashSet
由HashMap
支持,而HashMap
又由Entry
对象array
支持。
其中hash
用于查找array
的index
。
所以在HashSet
总是有一个元素的顺序( array
的顺序),你只是不能保证这个顺序是什么。
据我所知, HashSet
的顺序由其元素的计算hashes
的顺序决定(或至少影响)。
然后,对于相对简单的输入(例如您的单个字符串),人们可能会假设hashes
有严格的排序,这会给您看起来是自然的排序。
对于更复杂的对象,因此更复杂的hash
计算, hashes
将更加分散,并且排序“更加随机”。
此外,就像有人指出的那样,“不保证排序”并不意味着“保证随机排序”。
String
类的hashcode
方法也在这里发挥作用,对于单个字符String
s, hashcode
将只是String
一个char
的int
值。
并且由于char
的int
值按字母顺序排列,因此单个char
String
的计算hashes
值也是如此。
2楼
仅仅因为他们不能保证维持秩序并不意味着他们有时不会处于秩序状态。
如果您需要排序,请使用不同的集合 - 例如树集。
3楼
正如我们看到的文件
它不保证集合的迭代顺序; 特别是,它不保证订单会随着时间的推移保持不变。
它确实保持但不保证。 添加后随着时间的推移,删除几次您可以看到差异。
4楼
当然不是随机顺序,对于某个输入,迭代器的顺序是固定的,我想他们想说的顺序可能与输入顺序不同。
事实上,这里的顺序取决于String.hashCode()
、 String.equals()
和set.add()
调用的顺序。
当您调用System.out.print(set)
,您的意思是System.out.print(set.toString())
,而set.toString()
调用 set 的迭代器来访问所有元素。
5楼
HashSet 不保证它,但它并不意味着它必须更改顺序。 如果没有添加任何内容,则无需更改顺序。 例如看看这个例子
hs1.add("c");
hs1.add("b");
hs1.add("d");
hs1.add("g");
hs1.add(null);
hs1.add(null);
System.out.println(hs1);
输出: [null, b, c, d, g]
然后我们添加一个新元素并再次打印:
hs1.add("a");
System.out.println(hs1);
输出: [null, a, b, c, d, g]
如您所见,它在某种程度上改变了顺序。
没有什么是保证的,但这并不意味着它必须不遗余力地更改订单
6楼
HashSet
顺序不是随机的,它依赖于实现,并且实现可以自由更改。
JDK 8 中进行了显着更改。因此,如果您升级到 Java 8,您可能会看到HashMap
顺序发生了变化。
如果您使用像 IBM 这样的非 Oracle JDK,它也可能会有所不同。
一般来说,你永远不应该依赖它,否则你的程序将来可能会崩溃。
7楼
HashSet() 没有任何顺序。 它也不支持输入顺序。 但顺序不是随机的。 即使您更改版本并升级,该版本的输出也会更改并保持不变。 通过实现您的源代码,我得到了一些不同的答案,如下所示。 我已连续多次执行此代码,但输出相同。
[a, b, c, d, 空]
还有一件事,HashSet() 不支持重复,因此,添加重复的“null”只会增加代码的长度。
8楼
HashSet
使用来查找可能的重复项,并且必须在它们的散列 ( hashCode()
) 之后对列表中的对象进行排序才能这样做。