HashSet 输入为什么是有序的

来源:互联网 发布:1hhhhcom域名升级访问 编辑:程序博客网 时间:2024/05/17 23:48

首先,要明确“不保证有序”和“保证无序”不等价,HashSet的iterator是前者而不是后者,所以在一次运行中看到有序的结果也是正常的,但不能依赖这个有序行为。
况且HashSet并不关心key的“排序”,就算其iterator“有序”通常也是说“按元素插入顺序”(LinkedHashSet就支持插入顺序遍历)。题主在此看到的所谓“有序”纯粹是个巧合。
所以,想要确保有序并且集合中无重复元素,用HashTree稳妥。

通常插入HashSet的是Integer,其hashCode()实现就返回int值本身。所以在对象hashCode这一步引入了巧合的“按大小排序”。然后HashMap.hash(Object)获取了对象的hashCode()之后会尝试进一步混淆。JDK8版java.util.HashMap内的hash算法比JDK7版的混淆程度低;在[0, 2^32-1]范围内经过HashMap.hash()之后还是得到自己。单纯插入数字则正好落入这个范围内。外加load factor正好在此例中让这个HashMap没有hash冲突,这就导致例中元素正好按大小顺序插入在HashMap的开放式哈希表里。
这里修改把插入的数字先加上2的16次方,然后拿出来再减去2的16次方。

public class Test {


    public static void main(String[] args){
    Random rand=new Random(47);
        Set<Integer> intset=new HashSet<Integer>();
        Set<Integer> intset1=new TreeSet<Integer>();
        
        for (int i=0;i<10000;i++){
            intset.add(rand.nextInt(30) + (1 << 16));
            intset1.add(rand.nextInt(30) + (1 << 16));
        }
        Iterator<Integer> iterator=intset.iterator();
        Iterator<Integer> iterator1=intset1.iterator();
        while (iterator.hasNext()){
            System.out.print((iterator.next() - (1 << 16)) +" ");
        }
        System.out.println();
        while (iterator1.hasNext()){
            System.out.print((iterator1.next() - (1 << 16)) +" ");
        }
    }
}


HashSet输出:

16 17 18 19 20 21 22 23 24 25 26 27 28 29 1 0 3 2 5 4 7 6 9 8 11 10 13 12 15 14 

TreeSet输出:

0 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 


阅读全文
0 0
原创粉丝点击