为何有时候HashSet输出会有序?浅析HashSet底层是如何“排序”的

问题再现

我们都知道Set集合是无序的。此处的无序体现在,一般情况下,输出顺序和输入顺序不同。并且“毫无规律”(先挖个坑,后面解释)。比如如下代码:

		Set<Integer> s = new HashSet<>();
		s.add(37);
		s.add(16);
		s.add(4);
		s.add(23);
		s.add(1);
		s.add(6);
		s.add(66);
		System.out.println(s);// [16, 1, 66, 4, 37, 6, 23]
	}

可以看到,输出的顺序似乎是“不可预期”的。这似乎和我们所认知的一样。但是看下面代码:

		Set<Integer> s = new HashSet<>();

		s.add(2);
		s.add(1);
		s.add(4);
		s.add(7);
		s.add(6);
		s.add(5);
		s.add(3);
		System.out.println(s);// [1, 2, 3, 4, 5, 6, 7]

输入同样无序,但是输出却是有序的。为什么会这样呢?
我们先来看看HashSet的API文档怎么说的:
This class implements the Set interface, backed by a hash table (actually a HashMap instance). 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. This class permits the null element.
注意加粗的两句。翻译过来就是:它不保证集合的迭代顺序。特别是,它不能保证顺序会随着时间的推移保持恒定。
API文档说得很清楚了。不保证迭代顺序。也就是说不保证有序,但是也不保证无序。那HashSet的元素顺序真的是毫无规律不可预期的么?我们来看看HashSet底层究竟是怎样确定元素顺序的。

源码分析

先看看HashSet类的源码

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
   
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    /**
     * Constructs a new, empty set; the backing {@code HashMap} instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
   
        map = new HashMap<>();
    }
    
    public boolean add(E e) {
   
    	//为了保证元素唯一性,元素是作为HashMap的key来保存的
        return map.
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值