为什么类HashSet <t>在使用迭代器时已经对值进行了排序?</t>

时间:2015-01-13 19:49:32

标签: java iterator hashset

我在main方法上有以下代码,当我遍历Set并打印值时,值已经排序。原因是什么?

Set<Integer> set = new HashSet<Integer>();
set.add(2);
set.add(7);
set.add(3);
set.add(9);
set.add(6);

for(int i : set) {
    System.out.println(i);
}

输出:

2
3
6
7
9

3 个答案:

答案 0 :(得分:4)

这只是巧合。 HashSet不保留或保证任何订购。

  

它不保证集合的迭代顺序;在   特别是,它不保证订单将保持不变   随着时间的推移。

答案 1 :(得分:4)

我不确定这是巧合是正确的答案。没有机会参与其中。它是使用散列函数的结果,放在HashSet中的小值以及放入Set中的少量元素。

  • 对于Integer,hashCode()是整数的int值。

  • HashMap(和HashSet)对hashCode返回的值执行额外的散列处理,但是这个额外的散列不会更改您添加到HashSet中的小数字的值。 / p>

  • 最后,每个整数放入的存储桶是修改后的哈希码,模块化了HashSet的容量。 HashSet / HashMap的初始容量为16。

  • 因此2添加到桶2,7添加到桶7等...

  • 当您遍历HashSet的元素时,将按顺序访问存储桶,并且由于每个存储桶最多只有一个元素,因此您可以对数字进行排序。

以下是计算存储桶的方式:

int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);

static int hash(int h) { // for the small integers you put in the set, all the values being
                         // xored with h are 0, so hash(h) returns h
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

static int indexFor(int h, int length) {
     return h & (length-1); // table.length is the initial capacity - 16,
                            // so for h <= 15, indexFor(h,table.length)=h
}

因此,2,7,3,9,6的分别为2,7,3,9,6。

用于迭代HashSet的增强for循环按顺序访问存储桶,并且每个存储桶迭代其条目(存储在链表中)。因此,对于您的输入,首先访问2,然后访问3,6,7和9。

如果您添加的数字高于15,hash方法和indexFor方法(假设您没有更改HashSet的默认容量)将阻止数字排序当由HashSet迭代器迭代时。

答案 2 :(得分:2)

这只是一次意外。我试过了:

final Set<Integer> set = new HashSet<Integer>();
set.add(2);
set.add(17);
set.add(32);
set.add(92);
set.add(63);

我得到了17 32 2 92 63。它不在排序顺序中,因为HashSet不保留排序顺序或它们的添加顺序。