Java HashSet 的 无序和乱序

HashSet 无序、乱序问题

(1)定义
HashSet:一种没有重复元素的无序集合
解释:我们一般说HashSet是无序的,它既不能保证存储和取出顺序一致,更不能保证自然顺序(a-z)
数据结构:HashSet底层是HashMap
源码在new HashSet() 的时候,实际上是创建了一个HashMap实例对象

public HashSet() {
        map = new HashMap<>();
    }

(2)过程
通过一步一步分析源码,我们来看一看,这究竟是怎么一回事,首先我们先从程序的第一步——集合元素的存储开始看起,先看一看HashSet的add方法源码:

// HashSet 源码节选-JKD8
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
我们可以看到,HashSet直接调用HashMap的put方法,并且将元素e放到map的key位置(保证了唯一性 )

顺着线索继续查看HashMap的put方法源码:

//HashMap 源码节选-JDK8

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

而我们的值在返回前需要经过HashMap中的hash方法

接着定位到hash方法的源码:

//HashMap 源码节选-JDK8

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

hash方法的返回结果中是一句三目运算符,键 (key) 为null即返回 0,存在则返回后一句的内容

(h = key.hashCode()) ^ (h >>> 16)
JDK8中 HashMap——hash 方法中的这段代码叫做 “扰动函数”

从上面能了解到key.hashCode()是hash()计算的一个核心的函数,这个key,就是你放到set里面的对象。所以在不重新set里面对象的hashCode方法前,一次往set里面放数据再取出里是无序的,但之后再方数据,无论多少次,取出来的顺序都是与第一次取的顺序相同。

(3)应用
想用HashSet做乱序操作,可以把Set里面的对象的hashCode方法重写了,让他是随机的,每一次调用都不是同一个值,这样再map里面的put通过hash(key)确定位置的时候就能做到每次都不一样了

(4)例子
Java HashSet 的 无序和乱序_第1张图片
红框是重点,这样每次调用Objects.hash方法的时候,计算出来的code是不一样的

Java HashSet 的 无序和乱序_第2张图片
Java HashSet 的 无序和乱序_第3张图片
这是第一次
Java HashSet 的 无序和乱序_第4张图片
这是第二次

反例
Java HashSet 的 无序和乱序_第5张图片
把hashCode放注释掉
结果
Java HashSet 的 无序和乱序_第6张图片
第一次
Java HashSet 的 无序和乱序_第7张图片
第二次
由此验证看出,重写key的hashCode方法能做到set每次存放乱序

你可能感兴趣的:(java,数据结构)