【Java集合类】之 HashSet以及底层逻辑分析_hashset实现逻辑(1)

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 hs = new HashSet();

    //添加元素
    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集合添加一个元素的过程:**


![在这里插入图片描述](https://img-blog.csdnimg.cn/8e565abdf1a844f7b0132d7f24c7f787.png)


**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 extends AbstractSet implements Set, 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  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/b170ef17072e4ce5860caefe1683e8c9.png)


#### 第一次添加元素时🎐🎐🎐


根据元素的哈希值跟数组的长度计算出应存入的位置 例如:4  
 在判断当前 4 索引位置是否为null,如果是null直接存入  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/009c6e1b237e467e81ad278ce10f3e06.png)


#### 第二次添加元素时🎐🎐🎐


根据元素的哈希值跟数组的长度计算出的结果 是 10 索引位置  
 在判断当前位置是否为null,如果是null直接存入  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/edaa75b7da8f4cafb4ed4b81982b76c8.png)


#### 第三次添加元素时🎐🎐🎐


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


![在这里插入图片描述](https://img-blog.csdnimg.cn/c3f2691334a14d8793baf246082622de.png)


#### 第四次添加元素时🎐🎐🎐


根据元素的哈希值跟数组的长度计算出的结果 还是 4 索引位置  
 此时 4 索引上 已经有了两个元素  
 会通过equals方法比较 从上到下 一 一比较  
 如果一样,则不存,如果不一样,则存入数组,老元素挂在新元素下面  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/541340cb13064524b6b7de7ad34fae49.png)  
 **扩容**  
 当数组里面存了16\*0.75 =12个元素的时候,数组就会扩容为原先的**两倍** 32


**总结**


* **底层结构∶哈希表。(数组+链表)**
* **数组的长度默认为16,加载因子为0.75**
* **首先会先获取元素的哈希值,计算出在数组中应存入的索引**
* **判断该索引处是否为null**
* **如果是null,直接添加**
* **如果不是null,则与链表中所有的元素,通过equals方法比较属性值只要有一个相同,就不存,如果都不一样,才会存入集合。**




---



![img](https://img-blog.csdnimg.cn/img_convert/f811152cbc7fb1a5f240cef6c7ee013f.png)
![img](https://img-blog.csdnimg.cn/img_convert/a7bac4f59a1d758e482b1c1fb3bb4201.png)

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

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


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

[外链图片转存中...(img-XlFuvFDz-1714435507095)]

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

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


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

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值