JAVA集合之HashSet

  1. HashSet集合底层是HashMap
    public HashSet() {
        this.map = new HashMap();
    }
  1. HashSet添加步骤:添加元素时,先得到这个元素的hash值(并不止是直接取hashcode()方法的值,还会进行异或和无符号右移运算,如下图一),并转化索引值(并不等于实际放的位置的索引,真正的索引值还会进行下图二运算(var9)),这里我注意到了一点,当添加进集合的值是null时,该算法计算出来的索引值为0,所以null放进去的位置始终在集合第一位。
    static final int hash(Object var0) {
        int var1;
        return var0 == null ? 0 : (var1 = var0.hashCode()) ^ var1 >>> 16;
    }
        if ((var7 = var6[var9 = var8 - 1 & var1]) == null) {
            var6[var9] = this.newNode(var1, var2, var3, (HashMap.Node)null);
        }
  1. 随后判断当前table的大小,如果是第一次添加,则扩容table容量为16,并根据加载因子(默认0.75),算出临界值12,这个临界值意味着当table中已存在元素超过12(并不只是table数组容量的被占用量超过12,而是table数组+所有链表的被占用量超过12,可以理解为向HashSet中正确的添加了12个元素),即添加13个元素时,便进行扩容,扩容为原来的两倍,即32,以此类推。
        } else {
            var4 = 16;
            var5 = 12;
        }
  1. 随后找到存储数据表table,看这个索引位置是否已经存放了元素;若没有,则直接加入。
        if ((var7 = var6[var9 = var8 - 1 & var1]) == null) {
            var6[var9] = this.newNode(var1, var2, var3, (HashMap.Node)null);
        }
  1. 如果有,调用equals方法跟现链表上的节点逐一比较,如果相同,就放弃添加;如果不同,就添加到当前链表的末尾,在java8中,如果一条链表的元素个数到达xxx(默认8,没算上第一个节点P,算上就是到达9),并且table数组的大小>=xxx(默认64),该链表就会转变为红黑树(红黑树效率比链表更高);如果table数组的大小不足64,则扩容table数组,新的元素则继续放在该链表末尾,直到table数组容量到达64。
            if (((HashMap.Node)var7).hash == var1 && ((var11 = ((HashMap.Node)var7).key) == var2 || var2 != null && var2.equals(var11))) {
                var10 = var7;
            } else if (var7 instanceof HashMap.TreeNode) {
                var10 = ((HashMap.TreeNode)var7).putTreeVal(this, var6, var1, var2, var3);
            } else {
                int var12 = 0;

                while(true) {
                    if ((var10 = ((HashMap.Node)var7).next) == null) {
                        ((HashMap.Node)var7).next = this.newNode(var1, var2, var3, (HashMap.Node)null);
                        if (var12 >= 7) {
                            this.treeifyBin(var6, var1);
                        }
                        break;
                    }
  1. HashSet的table数组节点(即HashMap的节点)Node对象,其有四个属性,分别是hash、key、value、next(Node对象)。hash即key的hash值,key即存放的元素值;value是一个空对象(new Object()),所有节点共用一个它;next是一个新的Node对象,以便实现链表(可以理解为套娃)。
    static class Node<K, V> implements Entry<K, V> {
        final int hash;
        final K key;
        V value;
        HashMap.Node<K, V> next;

        Node(int var1, K var2, V var3, HashMap.Node<K, V> var4) {
            this.hash = var1;
            this.key = var2;
            this.value = var3;
            this.next = var4;
        }
    }
  1. 强调一点:元素超过第8个(到达第9个)时,判断子链表是否转化为红黑树;元素超过第12个(到达第13个)时,table数组开始扩容
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值