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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**