大数据最新【Java集合类】之 HashSet以及底层逻辑分析_hashset实现逻辑(1),2024年最新腾讯T3团队整理

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器在尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误做法:迭代器的快速失败行为应该仅用于检测 bug。

总结:HashSet集合特点

  • 底层数据结构是哈希表
  • 对集合的迭代顺序不做任何的保证,也就是说不保证存储和取出的元素顺序一致
  • 没有带索引的方法,所以不能使用普通for循环来遍历(可以使用迭代器和增强for遍历)
  • 由于是Set 集合,所以不包含重复元素的集合

1.2 HashSet 集合 Demo✨✨✨

代码示例:存储字符串并遍历

package com.ithmm_06;

import java.util.HashSet;
import java.util.Iterator;

/\*\*
 \* HashSet集合特点
 \*
 \* 底层数据结构是哈希表
 \* 对集合的迭代顺序不做任何的保证,也就是说不保证存储和取出的元素顺序一致
 \* 没有带索引的方法,所以不能使用普通for循环来遍历(可以使用迭代器和增强for遍历)
 \* 由于是Set 集合,所以不包含重复元素的集合
 \*/
public class HashSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        HashSet<String> hs = new HashSet<String>();

        //添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");

// hs.add("hello");


        //遍历
        for(String s:hs){
            System.out.println(s);//world java hello
        }
        //迭代器 Iterator<E> iterator() 
        // 返回对此 set 中元素进行迭代的迭代器 
        Iterator<String> it = hs.iterator();
        while (it.hasNext()) {
            String str = it.next();
            System.out.println(str);
        }
    }
}


1.3 HashSet集合保证元素唯一性底层逻辑(源码分析)🎊🎊🎊

HashSet集合添加一个元素的过程:

在这里插入图片描述

HashSet底层源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package java.util;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap.KeySpliterator;

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
    static final long serialVersionUID = -5024744406713321676L;
    private transient HashMap<E, Object> map;
    private static final Object PRESENT = new Object();

    public HashSet() {
        this.map = new HashMap();
    }

    public HashSet(Collection<? extends E> var1) {
        this.map = new HashMap(Math.max((int)((float)var1.size() / 0.75F) + 1, 16));
        this.addAll(var1);
    }

    public HashSet(int var1, float var2) {
        this.map = new HashMap(var1, var2);
    }

    public HashSet(int var1) {
        this.map = new HashMap(var1);
    }

    HashSet(int var1, float var2, boolean var3) {
        this.map = new LinkedHashMap(var1, var2);
    }

    public Iterator<E> iterator() {
        return this.map.keySet().iterator();
    }

    public int size() {
        return this.map.size();
    }

    public boolean isEmpty() {
        return this.map.isEmpty();
    }

    public boolean contains(Object var1) {
        return this.map.containsKey(var1);
    }

    public boolean add(E var1) {
        return this.map.put(var1, PRESENT) == null;
    }

    public boolean remove(Object var1) {
        return this.map.remove(var1) == PRESENT;
    }

    public void clear() {
        this.map.clear();
    }

    public Object clone() {
        try {
            HashSet var1 = (HashSet)super.clone();
            var1.map = (HashMap)this.map.clone();
            return var1;
        } catch (CloneNotSupportedException var2) {
            throw new InternalError(var2);
        }
    }

    private void writeObject(ObjectOutputStream var1) throws IOException {
        var1.defaultWriteObject();
        var1.writeInt(this.map.capacity());
        var1.writeFloat(this.map.loadFactor());
        var1.writeInt(this.map.size());
        Iterator var2 = this.map.keySet().iterator();

        while(var2.hasNext()) {
            Object var3 = var2.next();
            var1.writeObject(var3);
        }

    }

    private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        var1.defaultReadObject();
        int var2 = var1.readInt();
        if (var2 < 0) {
            throw new InvalidObjectException("Illegal capacity: " + var2);
        } else {
            float var3 = var1.readFloat();
            if (!(var3 <= 0.0F) && !Float.isNaN(var3)) {
                int var4 = var1.readInt();
                if (var4 < 0) {
                    throw new InvalidObjectException("Illegal size: " + var4);
                } else {
                    var2 = (int)Math.min((float)var4 \* Math.min(1.0F / var3, 4.0F), 1.07374182E9F);
                    this.map = (HashMap)(this instanceof LinkedHashSet ? new LinkedHashMap(var2, var3) : new HashMap(var2, var3));

                    for(int var5 = 0; var5 < var4; ++var5) {
                        Object var6 = var1.readObject();
                        this.map.put(var6, PRESENT);
                    }

                }
            } else {
                throw new InvalidObjectException("Illegal load factor: " + var3);
            }
        }
    }

    public Spliterator<E> spliterator() {
        return new KeySpliterator(this.map, 0, -1, 0, 0);
    }
}



1.4 常见数据结构之哈希表🎐🎐🎐

HashSet底层是哈希表结构的

哈希表

  • JDK8之前,底层采用数组+链表实现。
  • JDK8以后,底层进行了优化。由数组+链表+红黑树实现。
一、HashSet1.7版本原理解析🎐🎐🎐

当我们用空参构造 创建一个Hashset 时

       HashSet<String> haset1 = new HashSet<>();

底层 创建一个默认长度16,默认加载因子0.75的数组,数组名table
在这里插入图片描述

第一次添加元素时🎐🎐🎐

根据元素的哈希值跟数组的长度计算出应存入的位置 例如:4
在判断当前 4 索引位置是否为null,如果是null直接存入
在这里插入图片描述

第二次添加元素时🎐🎐🎐

根据元素的哈希值跟数组的长度计算出的结果 是 10 索引位置
在判断当前位置是否为null,如果是null直接存入
在这里插入图片描述

第三次添加元素时🎐🎐🎐

根据元素的哈希值跟数组的长度计算出的结果 还是 4 索引位置
此时 4 索引上 已经有了一个元素 不为null ,则会调用equals方法比较 内部的属性值
如果一样,则不存,如果不一样,则存入数组,老元素挂在新元素下面 形成链表结构

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

053664404)]
[外链图片转存中…(img-o8fkpFfh-1715053664405)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值