背景 在练习java
Set
时,遇到了很奇怪的问题。我们都知道,Set
是无序的并且不能有重复元素的,利用随机数随机存入多个Integer
类型的数据,却发生了有序的情况。
1 2 3 4 5 6 7 8 9 Set<Integer> set = new HashSet<>(); while (set.size() < 16 ) { int num = (int ) (Math.random() * 16 ); if (!set.contains(num)) { set.add(num); } } System.out.println(set);
运行结果:
1 [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ]
明明Set
是无序的,怎么存进去就自动进行了排序?
解决 依旧是万能的百度。
从https://bbs.csdn.net/topics/393667463获取到了想要的答案。
总结一句话:HashSet
的是计算对象的hash
值,并映射到数组的下标。
一般来说的Set
无序是指不按照我们存入的顺序 。
接下来引用大佬的解答。
HashSet
的原理是:计算对象的hash
值,并映射到数组的下标。
再看一下String
的hashCode()
方法的源码
哈希值是通过char
对应的int
值计算出来的,即:char
对应的int
值越大,hash
值就越大。
而在拉丁字母A、B、C、D的char
字符对应的int
值恰巧是递增的 ,所以他们的hash
值也恰巧是递增的,所以最终映射到HashSet
内的数组的位置也是顺序的。
HashSet
元素的存储(地址)是无序的。一般来讲,通过进行迭代的迭代器也是依次将各个元素(字符串),无序地输出。
楼主所示的”有序结果”,其实是一种极其特殊案例 :每个元素都仅是一(单)个字符,或都是数字字符,或都是小写英文字符,或都是大写英文字符。
元素的存储地址,视这个元素的哈希值而定。 由于元素仅有一个字符,其哈希值的计算结果,就会是这个给定字符的 ascii 码(参见: 哈希算法)的值。结果, 打印出的 HashSet
列表,就会是貌似经过排序后的结果。但要注意构成这种案例的条件:元素必须 都是单个数字字符、或都是单个英文小写字符、或都是单个英文大写字符。
下列代码显示每个元素的哈希值,以及最终调用 toString()
输出 HashSet hs
的结果。输出结果显示,单个字符元素的哈希值,就是它的 ASCII值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.HashSet;public class HashSetDemo { static void showHashSet (String[] s) { HashSet<String> hs = new HashSet<String>(); for (int i = 0 ; i < s.length; i++) { hs.add(s[i]); System.out.println(s[i] + "的哈希值:" + s[i].hashCode() + " " ); } System.out.println("toString的结果:" + hs); } public static void main (String args[]) { String data[][] = new String[5 ][6 ]; String dat[] = { "B" , "A" , "D" , "E" , "C" , "F" , "6" , "4" , "3" , "1" , "2" , "5" , "BB" , "AA" , "DD" , "EE" , "CC" , "FF" , "42" , "41" , "45" , "46" , "44" , "43" , "Base" , "Alberta" , "Done" , "End" , "Coding" , "Factory" }; for (int i = 0 ; i < dat.length; i++) data[i / 6 ][i % 6 ] = dat[i]; for (int i = 0 ; i < data.length; i++) showHashSet(data[i]); } }
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 B的哈希值:66 A的哈希值:65 D的哈希值:68 E的哈希值:69 C的哈希值:67 F的哈希值:70 toString的结果:[A, B, C, D, E, F] 6 的哈希值:54 4 的哈希值:52 3 的哈希值:51 1 的哈希值:49 2 的哈希值:50 5 的哈希值:53 toString的结果:[1 , 2 , 3 , 4 , 5 , 6 ] BB的哈希值:2112 AA的哈希值:2080 DD的哈希值:2176 EE的哈希值:2208 CC的哈希值:2144 FF的哈希值:2240 toString的结果:[BB, AA, DD, EE, CC, FF] 42 的哈希值:1662 41 的哈希值:1661 45 的哈希值:1665 46 的哈希值:1666 44 的哈希值:1664 43 的哈希值:1663 toString的结果:[44 , 45 , 46 , 41 , 42 , 43 ] Base的哈希值:2063089 Alberta的哈希值:743772625 Done的哈希值:2135970 End的哈希值:69819 Coding的哈希值:2023747466 Factory的哈希值:572770538 toString的结果:[Done, Alberta, Coding, Factory, End, Base]