Java HashSet顺序及其与jdk7/8的区别
这是一个由两部分组成的问题:Java HashSet顺序及其与jdk7/8的区别,java,collections,hashset,Java,Collections,Hashset,这是一个由两部分组成的问题: HashSet是否实现了某种隐藏的排序机制,或者只是引用文档:它不保证集合的迭代顺序;特别是,它不能保证顺序在一段时间内保持不变。告诉我,顺序在将来可能会发生变化和/或取决于内存使用情况 为什么我在JDK之间切换时会得到完全不同的“排序”(我敢说) 举个例子: for (int i = 0; i < 1000; i++) { Set<String> stringSet = new HashSet<>();
它不保证集合的迭代顺序;特别是,它不能保证顺序在一段时间内保持不变。
告诉我,顺序在将来可能会发生变化和/或取决于内存使用情况for (int i = 0; i < 1000; i++) {
Set<String> stringSet = new HashSet<>();
stringSet.add("qwe");
stringSet.add("rtz");
stringSet.add("123");
stringSet.add("qwea");
stringSet.add("12334rasefasd");
stringSet.add("asdxasd");
stringSet.add("arfskt6734");
stringSet.add("123121");
stringSet.add("");
stringSet.add("qwr");
stringSet.add("rtzz");
stringSet.add("1234");
stringSet.add("qwes");
stringSet.add("1234rasefasd");
stringSet.add("asdxasdq");
stringSet.add("arfskt6743");
stringSet.add("123121 ");
stringSet.add(" ");
System.out.println(stringSet);
}
for(int i=0;i<1000;i++){
Set stringSet=newhashset();
添加(“qwe”);
添加(“rtz”);
stringSet.添加(“123”);
添加(“qwea”);
stringSet.add(“12334rasefasd”);
stringSet.add(“asdxasd”);
添加(“arfskt6734”);
stringSet.添加(“123121”);
stringSet.add(“”);
添加(“qwr”);
添加(“rtzz”);
stringSet.添加(“1234”);
添加(“qwes”);
stringSet.add(“1234rasefasd”);
添加(“asdxasdq”);
stringSet.add(“arfskt6743”);
stringSet.添加(“123121”);
stringSet.add(“”);
System.out.println(stringSet);
}
无论运行多少次,都将产生以下输出:
JDK 7:[、123、qwea、asdxasdq、qwe、qwr、123121、arfskt6743、1234rasefasd、qwes、rtz、rtzz、1234、12334rasefasd、asdxasd、arfskt6734、123121]
JDK 8:[、qwes、arfskt6743、asdxasdq、123121、123121、arfskt6734、qwr、1231234、qwea、rtzz、rtz、12334rasefasd、1234rasefasd、qwe、asdxasd]
显然,空字符串和纯空白字符串在这两个方面都处于领先地位,但其余部分则完全不同。根据集合更新 7u6中添加的可选字符串哈希函数已从JDK 8中删除,同时删除了JDK.map.althashing.threshold系统属性。相反,包含大量冲突键的散列箱通过将其条目存储在平衡树而不是链表中来提高性能。此JDK 8更改仅适用于HashMap、LinkedHashMap和ConcurrentHashMap 在极少数情况下,此更改可能会更改HashMap和HashSet的迭代顺序。没有为HashMap对象指定特定的迭代顺序-任何依赖于迭代顺序的代码都应该是固定的
所以,基本上 哈希集的算法已更改,以提高性能。它变为平衡树而不是链表 这种更改可能会更改集合的迭代顺序,并且确定这种行为应该由您解决,如果您依赖它的话 您正在看到一个更好的集合实现,这看起来可能是有序的,但这纯粹是巧合 我建议您不要依赖集合的迭代顺序,因为该顺序不是保证 @编辑 另一个概念也很重要,正如用户Holger所说 默认情况下不使用Java7的“可选字符串哈希函数”。此外,平衡树仅适用于桶碰撞场景。然而,作为这一改进的结果,另一个未提及的变化已经发生。对象的哈希代码到数组位置的映射经历了从Java7到Java8的简化转换
答1:是的,Hashset不维护插入顺序,但在这之后,如果您迭代它,每次都会得到相同的顺序 Ans 2:迭代结果可能与java版本不同,因为它取决于该版本的哈希代码实现。
但是Hashset提供了一个保证,即在插入元素后,如果每次迭代都会在该java版本中获得相同的顺序,那么迭代顺序将永远不会得到更改。Hashset的内部存储由一个算法定义。它不是随机化的 该规范(API)没有指定任何特定的算法,只是基于散列。实现可以选择它想要的任何算法,并且可以在将来的版本中自由选择不同的算法 然而,由于基于算法,这意味着对于任何特定版本的实现(Oracle vs IBM,7 vs 8,…),添加一组特定的值将始终产生相同的结果,即排序
特定版本的顺序是一致的,但它是未定义的,在未来的版本和/或不同的实现中可能会更改,恕不另行通知,因此您应该永远不要依赖顺序。要获得更令人兴奋的内容,请将示例代码更改为
public static void main(String... args) {
System.out.println(System.getProperty("java.version"));
List<String> strings=Arrays.asList("qwe", "rtz", "123", "qwea",
"12334rasefasd", "asdxasd", "arfskt6734", "123121", "", "qwr",
"rtzz", "1234", "qwes", "1234rasefasd", "asdxasdq", "arfskt6743",
"123121 ", " ");
for (int i = 5; i < 26; i++) {
Set<String> stringSet = new HashSet<>(1<<i);
stringSet.addAll(strings);
System.out.println(stringSet);
}
}
1.8.0_111
[、qwes、arfskt6743、asdxasdq、123121、123121、arfskt6734、qwr、123、1234、qwea、rtzz、rtz、12334rasefasd、1234rasefasd、qwe、asdxasd]
[、123121、arfskt6734、qwr、1234、asdxasd、qwes、arfskt6743、asdxasdq、123121、123、qwea、rtzz、rtz、12334rasefasd、1234rasefasd、qwe]
[、arfskt6734、qwr、arfskt6743、asdxasdq、123、rtzz、123121、1234、asdxasd、qwes、123121、qwea、rtz、12334rasefasd、1234rasefasd、qwe]
[,qwr,,123,rtzz,1234,asdxasd,qwes,123121,qwea,rtz,1234rasefasd,arfskt6734,arfskt6743,asdxasdq,123121,12334rasefasd,qwe]
[、123、1234、rtz、arfskt6734、arfskt6743、asdxasdq、123121、12334rasefasd、qwe、qwr、rtzz、asdxasd、qwes、123121、qwea、1234rasefasd]
[、1234、asdxasdq、123121、12334rasefasd、rtzz、asdxasd、qwes、123121、qwea、123、rtz、arfskt6734、arfskt6743、qwe、qwr、1234rasefasd]
[、1234、12334rasefasd、qwes、qwea、rtz、asdxasdq、123121、rtzz、asdxasd、123121、123、arfskt6734、arfskt6743、qwe、qwr、1234rasefasd]
[、asdxasdq、rtzz、123121、arfskt6734、arfskt6743、qwe、qwr、1234、12334rasefasd、qwes、qwea、rtz、123121、asdxasd、123、1234rasefasd]
[,asdxas
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);