为什么我的程序的 HashSet 顺序总是相同的?
Why HashSet order always same for my program?
对于一些教程,他们说:
HashSet doesn’t maintain any order, the elements would be returned in any random order.
但是我写了一个测试程序,结果总是一样。
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]
我试了很多次,但顺序总是一样的。为什么?希望有人能帮助我,在此先感谢!
不能保证维持秩序并不意味着它们有时不会秩序井然。
如果您需要排序,请使用不同的集合 - 例如树集。
如我们所见文档
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
它确实保持但不保证。随着时间的推移,你添加,删除几次你可以看到差异。
当然不是随机顺序,对于某个输入,迭代器的顺序是固定的,我想他们想说的顺序可能与输入顺序不同。
事实上,这里的顺序取决于 String.hashCode()
、 String.equals()
和 set.add()
invoke.
的顺序
当您调用 System.out.print(set)
时,您的意思是 System.out.print(set.toString())
,并且 set.toString()
调用 set 的迭代器来访问所有元素。
此行为的原因是 HashSet
由 HashMap
支持,而 HashMap
又由 array
个 Entry
对象支持。其中 hash
用于查找 array
的 index
。所以在 HashSet
中总是有一个元素的顺序(array
的顺序),你只是不能保证这个顺序是什么。
据我从代码中可以看出,HashSet
的顺序由其元素的计算 hashes
的顺序决定(或至少受到影响)。然后,对于相对简单的输入(比如您的单个字符串),人们可能会假设 hashes
有严格的排序,这会给您带来看似自然的排序。对于更复杂的对象,因此更复杂的 hash
计算,hashes
将更加分散,并且排序 "more random".
此外,就像已经指出的那样,"no guarantee of ordering" 并不意味着 "guaranteed random ordering"。
String
class 的 hashcode
方法也在这里发挥作用,对于单个字符 String
s hashcode
将只是int
String
中第一个 char
的值。由于 char
的 int
值是按字母顺序排列的,因此单个 char
String
的计算 hashes
也是如此。
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]
如您所见,它在一定程度上改变了顺序。
没有什么是可以保证的,但这并不意味着它必须特意改变顺序
HashSet
顺序不是随机的,它取决于实现并且实现可以自由更改。 JDK 8 中进行了显着更改。因此,如果您升级到 Java 8,您可能会看到 HashMap
顺序已更改。如果您使用像 IBM 这样的非 Oracle JDK,它也可能会有所不同。一般来说,你永远不应该依赖它,否则你的程序将来可能会崩溃。
HashSet() 没有任何排序。它也不支持输入顺序。但顺序不是随机的。即使您更改版本并升级,输出也会更改并与该版本保持相同。通过实施您的源代码,我得到了一些不同的答案,如下所示。我已经连续多次执行这段代码,但输出是一样的。
[a, b, c, d, 空]
还有一点,HashSet() 不支持重复,因此,添加重复 "null" 只会增加代码的长度。
HashSet
使用 binary search 查找可能的重复项,并且必须在哈希 (hashCode()
) 之后对列表中的对象进行排序才能这样做。
对于一些教程,他们说:
HashSet doesn’t maintain any order, the elements would be returned in any random order.
但是我写了一个测试程序,结果总是一样。
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]
我试了很多次,但顺序总是一样的。为什么?希望有人能帮助我,在此先感谢!
不能保证维持秩序并不意味着它们有时不会秩序井然。
如果您需要排序,请使用不同的集合 - 例如树集。
如我们所见文档
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
它确实保持但不保证。随着时间的推移,你添加,删除几次你可以看到差异。
当然不是随机顺序,对于某个输入,迭代器的顺序是固定的,我想他们想说的顺序可能与输入顺序不同。
事实上,这里的顺序取决于 String.hashCode()
、 String.equals()
和 set.add()
invoke.
当您调用 System.out.print(set)
时,您的意思是 System.out.print(set.toString())
,并且 set.toString()
调用 set 的迭代器来访问所有元素。
此行为的原因是 HashSet
由 HashMap
支持,而 HashMap
又由 array
个 Entry
对象支持。其中 hash
用于查找 array
的 index
。所以在 HashSet
中总是有一个元素的顺序(array
的顺序),你只是不能保证这个顺序是什么。
据我从代码中可以看出,HashSet
的顺序由其元素的计算 hashes
的顺序决定(或至少受到影响)。然后,对于相对简单的输入(比如您的单个字符串),人们可能会假设 hashes
有严格的排序,这会给您带来看似自然的排序。对于更复杂的对象,因此更复杂的 hash
计算,hashes
将更加分散,并且排序 "more random".
此外,就像已经指出的那样,"no guarantee of ordering" 并不意味着 "guaranteed random ordering"。
String
class 的 hashcode
方法也在这里发挥作用,对于单个字符 String
s hashcode
将只是int
String
中第一个 char
的值。由于 char
的 int
值是按字母顺序排列的,因此单个 char
String
的计算 hashes
也是如此。
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]
如您所见,它在一定程度上改变了顺序。
没有什么是可以保证的,但这并不意味着它必须特意改变顺序
HashSet
顺序不是随机的,它取决于实现并且实现可以自由更改。 JDK 8 中进行了显着更改。因此,如果您升级到 Java 8,您可能会看到 HashMap
顺序已更改。如果您使用像 IBM 这样的非 Oracle JDK,它也可能会有所不同。一般来说,你永远不应该依赖它,否则你的程序将来可能会崩溃。
HashSet() 没有任何排序。它也不支持输入顺序。但顺序不是随机的。即使您更改版本并升级,输出也会更改并与该版本保持相同。通过实施您的源代码,我得到了一些不同的答案,如下所示。我已经连续多次执行这段代码,但输出是一样的。
[a, b, c, d, 空]
还有一点,HashSet() 不支持重复,因此,添加重复 "null" 只会增加代码的长度。
HashSet
使用 binary search 查找可能的重复项,并且必须在哈希 (hashCode()
) 之后对列表中的对象进行排序才能这样做。