当我在代码下面运行时,它始终以自然/字母顺序给出o / p。据我所知,HashSet
没有对条目进行排序。我知道HashSet
由HashMap
支持,而不是LinkedHashMap
。我尝试浏览HashSet
和HashMap
的源代码,但无法找到此行为的代码。
从源代码中可以看到HashSet
类中的构造函数:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
使用LinkedHashMap
。如果我使用过这个构造函数,我会认为这就是这种行为的原因,但我没有使用这个构造函数。
有人可以解释一下这种行为的原因/代码吗?
这是我的简单代码:
Set<String> mySet = new HashSet<>();
mySet.add("D");
mySet.add("B");
mySet.add("1");
mySet.add("E");
mySet.add("A");
mySet.add("F");
mySet.stream().forEach(x -> System.out.println(x));
OP:
1
A
B
D
E
F
答案 0 :(得分:2)
这是巧合,因为默认的HashSet大于散列的范围且没有碰撞,并且字符串的散列最终按字母顺序排列。
这是String.hashCode:
的代码 public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
正如您所看到的,单字符字符串的哈希最终只是字符值。
HashSet的default capacity为16,这意味着您的所有值最终都会显示在存储区char value % 16
中,结果为您的示例的字母顺序。试试&#34; 2&#34;而不是&#34; 1&#34;,例如,这应该在&#34; A&#34;之后结束。即使你交换了&#34; A&#34;和&#34; 1&#34;这也应该在输出中交换它们。请参阅Ascii table。
答案 1 :(得分:1)
此类实现Set接口,由哈希表(实际上是HashMap实例)支持。它不能保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。
换句话说,你不能依赖HashSet中元素的顺序。
答案 2 :(得分:0)
使用以下代码,您会看到添加元素的哈希码按升序排列:
Set<String> mySet = new HashSet<>();
mySet.add("D");
mySet.add("B");
mySet.add("1");
mySet.add("E");
mySet.add("A");
mySet.add("F");
mySet.stream()
.forEach(x -> System.out.println(x + " : " + x.hashCode()));
System.out.println(mySet);
1:49
A:65
B:66
D:68
E:69
F:70
[1,A,B,D,E,F]
这里您使用了一个非常特别的示例:您只添加了包含单个字符(字母或数字)的String
。
由于这些代码的哈希码对应于它们的ASCII代码,因此您可以获得符合ASCCI顺序的可预测顺序。
不同的哈希码值在HashMap
实现中由数组的不同元素物理表示:
transient Node<K,V>[] table;
Iterator
的{{1}}迭代按索引索引的数组元素
而结果。
现在,HashMap
用于迭代的ASCII顺序看起来像数字和字母字符的自然顺序,仅适用于非常简单的情况,其中添加的Map
仅由...组成1个字母或1个数字。
添加包含多个字符的String
,您将有一个不可预测的顺序:
String
90000:54118329
妈妈:77733
15454:46883119
爸爸:68455[90000,妈妈,15454,爸爸]
答案 3 :(得分:0)
长度为1的字符串的hashCode只是唯一的char,其哈希码是它自己的数值。 Voilà,全部都是订购的。
对于具有相同前缀,长度相同且与安全漏洞相关的字符串,也可以找到这种现象。 (我相信MD5需要人工种子。)
答案 4 :(得分:0)
这对于生成有序哈希的测试/工作数据集来说只是巧合。我在你的套装中添加了一些元素。尝试运行以下代码,我想你会得到你的答案。
Set<String> mySet = new HashSet<>();
mySet.add("D");
mySet.add("B");
mySet.add("1");
mySet.add("E");
mySet.add("A");
mySet.add("F");
mySet.add("C");
mySet.add("Z");
mySet.add("M");
mySet.add("Q");
mySet.stream().forEach(x -> System.out.println(x));
这是我的输出(不是自然顺序): 1 一个 Q 乙 C d Ë F ž 中号