什么是HashSet

在 Java 中,HashSet 是一个基于哈希表实现的集合类,它实现了 Set 接口

HashSet 的主要特点是:1,2

HashSet 的主要特点是

1,集合中的数据不能够重复

2,存储的数据是无序的(元素的存储顺序与插入顺序无关)

3,允许 null 值: 可以存储一个 null 元素(感觉这个不算)

HashSet 的常用方法

boolean add(e)向集合中添加元素。如果元素已存在,则返回 false。

boolean remove(Object o)从集合中移除指定元素。如果元素存在并成功移除,则返回 true。

boolean contains(Object o)检查集合中是否包含指定元素。如果存在,则返回 true。

int size() 返回集合中元素的数量。

boolean isEmpty()检查集合是否为空。如果为空,则返回 true。

void clear()清空集合中的所有元素。

Iterator iterator() 返回一个迭代器,用于遍历集合中的元素。

Object[] toArray() 将集合转换为数组。

hasSet存储为啥是无序的

hasSet 存储为啥数据不能够重复

hash存储是幂等性算法

也就是说:你给我一个A,计算出来的是2。

下次你再给一个A,计算出来的仍然是2。

这样的话,就会造成一个问题。

这个2要不要存储呢?

hasSet会丢弃第2个相同的值,因此存储的数据是不能够重复的。

存储数据是无序的

package part;
// HashSet在util这个包中,需要我们引入
import java.util.HashSet;
public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("赵6");
// 输出的来是: [赵6, 李四, 张三] 说明存储数据是无序的
System.out.println(setObject);
}
}

存储的数据是不会重复的

public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("张三");
// 输出的来是:
System.out.println(setObject);
}
}

HashSet如何修改数据

HashSet无法直接修改数据。

我们需要先把某一条要修改的数据删除掉。在新增我们想要的数据

package part;
// HashSet在util这个包中,需要我们引入
import java.util.HashSet; public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
// 把张三更改为张3,我们先删除然后再新增
setObject.remove("张三");
setObject.add("张3");
// 输出: [李四, 张3]
System.out.println(setObject);
}
}

增强 for循环(也称为 for-each 循环) 来遍历数据

package part;
// HashSet在util这个包中,需要我们引入
import java.util.HashSet;
public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 我们通过特殊for循环来遍历数据
for (Object o : setObject) {
System.out.println(o);
}
}
}

增强 for循环的语法

for (元素类型 变量名 : 数组或集合) {
// 循环体
// ps: 变量名是循环中的每一项
}

HashSet.add新增元素(如果元素已存在,则返回 false)

package part;
// HashSet在util这个包中,需要我们引入
import java.util.HashSet;
public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 输出的是 [李四, 张三, 王五]
System.out.println(setObject);
}
}

HashSet.addAll 将一个集合中的所有元素添加到另一个集合中

package part;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
ArrayList<Integer> listObject = new ArrayList();
listObject.add(1);
listObject.add(2);
LinkedList linkedListObject = new LinkedList();
linkedListObject.add("张三");
// 添加一个ArrayList集合对象
setObject.addAll(listObject);
// 添加一个LinkedList集合对象
setObject.addAll(linkedListObject);
// 输出的是: [1, 2, 张三]
System.out.println("setObject:" + setObject);
}
}

HashSet.toArray 将HashSet转化为数组

public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 将 HashSet 转换为数组
Object obj = setObject.toArray();
System.out.println(obj);
}
}

HashSet.size() 获取HashSet 的长度

public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 获取HashSet 的长度
int len = setObject.size();
System.out.println(len);
}
}

HashSet.clone 克隆

package part;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 克隆HashSet,相当于复制了一份。但是我们需要使用Object来声明
Object newSet = setObject.clone();
}
}

克隆 HashSet 可以不用Object来声明吗?

克隆 HashSet 可以不用 Object 来声明吗? 可以的。

那为啥克隆需要使用 Object来声明呢?

因为:clone() 方法的返回类型是 Object。所以我们需要使用Object来声明。

我们可以使用强制转化来处理就行

public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 克隆HashSet,相当于复制了一份。我们可以使用强制转化来解决这个问题的
HashSet newSet =(HashSet) setObject.clone();
}
}

HashSet.remove(被移除的对象)

要从 HashSet 中移除的对象。如果 HashSet 包含该对象,则会被移除。

返回值是一个布尔值

如果 HashSet 中包含指定的对象并且成功移除,则返回 true。

如果 HashSet 中不包含该对象,则返回 false。

public class Java01 {
public static void main(String[] args) {
HashSet setObject = new HashSet();
setObject.add("张三");
setObject.add("李四");
setObject.add("王五");
// 移除李四
Boolean delStatus = setObject.remove("李四");
// 输出的是true
System.out.println(delStatus);
}
}

ArrayList.remove根据传参不同,返回的类型不同

ArrayList arrList = new ArrayList();
arrList.add("嘿嘿01");
// 传参的是数字,返回的是被删除的数据
Object oldValue = arrList.remove(0);
public class Java01 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("A");
// 传参字符串,返回来的是布尔
Boolean flag = list.remove("A");
System.out.println(flag);
}
}

HashSet存储了相同的数据

package part;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; public class Java01 {
public static void main(String[] args) {
HashSet setList = new HashSet();
User u1 = new User();
User u2 = new User();
u1.id = "2025_01_30";
u1.name = "张三";
u2.id = "2025_01_30";
u2.name = "张三";
setList.add(u1);
setList.add(u2);
// 大家认为会输出什么呢?
// 输出的 [User [id=2025_01_30, name=张三], User [id=2025_01_30, name=张三]]
System.out.println(setList);
}
} class User{
String id;
String name;
// ctrl + o 就可以啦 现在我重写了 toString
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}

不是说:HashSet中的数据不能重复吗?

为啥会重复呢?

因为:这2个对象在内存中是不同的地址哈~。

所以HashSet会认为是不同的值。

内存中是不同的地址我们一般认为是 hashCode不同(这种说法不准确,但是方便我们理解)

ps: hashCode类似与内存中的地址

解释为啥存储了相同的数据


package part;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; public class Java01 {
public static void main(String[] args) {
HashSet setList = new HashSet();
User u1 = new User();
User u2 = new User();
u1.id = "2025_01_30";
u1.name = "张三";
u2.id = "2025_01_30";
u2.name = "张三";
setList.add(u1);
setList.add(u2);
// hashCode 我们可以理解为内存中的地址(这种说法不准确,但是方便我们理解)
System.out.println(u1.hashCode()); // 685325104
System.out.println(u2.hashCode()); // 460141958
// 我们发现这2个地址不同,就会认为是2个不同的对象,就会出现相同的数据
}
} class User{
String id;
String name;
// ctrl + o 就可以啦
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}

如何如果让一个对象的id和name相同,就让它识别为是同一个数据

如果让一个对象的id和name相同,就让它识别为是同一个数据呢?

是可以的。我们需要重写2个方法;hashCode 和 equals

因为: HashSet是在存储数据的时候,就是通过hashCode来操作的。

我们给定一个值(字符串), 通过操作得到存储到哪一个位置。

当然不同的值可能得到的存储位置是一样的。

如果出现这样的情况,他会去比较他们的equals。

如果相等,会把这个数据(后面这个新增的数据)丢弃,什么都不做。

如果不相等,这个时候他会使用链表它装在一起哈。

我们也可以从这里得出结论:HashSet的底层是:数组+链表的结构来进行存储数据的

重写hashCode 和 equals


package part;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; public class Java01 {
public static void main(String[] args) {
HashSet setList = new HashSet();
User u1 = new User();
User u2 = new User();
u1.id = 2025;
u1.name = "张三";
u2.id = 2025;
u2.name = "张三";
setList.add(u1);
setList.add(u2);
// [User [id=2025, name=张三]] 现在数据就不会重复了
System.out.println(setList);
}
} class User{
int id;
String name;
// 重写方法的快捷键 ctrl+o
@Override
// 类似与我们的内存地址,我们使用id来判断
public int hashCode() {
return id;
} @Override
// 判断2个对象的属性是否完全相同
public boolean equals(Object obj) {
if(obj instanceof User) {
//因为这个对象是User类型的,我们可以使用强制转换
User u = (User)obj;
//判断对象的属性是否相同,这里为啥使用equals,等会回说一下
if(u.id==this.id && u.name.equals(this.name)) {
return true;
}else{
return false;
}
}else{
// 如果不是,直接返回false
return false;
}
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}

HashSet的底层是:数组+链表的结构来进行存储数据的

== 和 equals的区别

1,当使用 == 比较基本数据类型,它比较的是两个变量的值是否相等。

2,当使用 == 比较引用数据类型(如对象)时,它比较的是对象的内存地址是否相等,即它们是否引用同一内存地址。

3,equals是Object类中的一个方法,用于比较同一类的两个对象的内容是否相等。

equals的比较逻辑

equals方法首先检查两个对象是否为同一类的实例(即类是否相等)。

如果不属于同一类,则对象肯定不相等。

如果类相等,equals方法将逐一比较两个对象的字段或属性,以确定它们是否相等。

尾声

准备开始学习java了。

今天学习的第三天,每天都会发文章,我要卷起来。

请小伙伴们监督我,奥利给

java中的HashSet的更多相关文章

  1. java中的hashSet和Treeset的分析

    hashset中的元素 treeset中的元素要实现comparable接口

  2. Java中的HashSet和TreeSet

    1:Set集合(理解) (1)Set集合的特点 无序,唯一 (2)HashSet集合(掌握) A:底层数据结构是哈希表(是一个元素为链表的数组) B:哈希表底层依赖两个方法:hashCode()和eq ...

  3. java中集合类HashSet、ArrayList、LinkedList总结

    [HashSet] 1. HashSet存储不能够存储相同的元素,元素是否相同的判断:重写元素的equals方法.equals方法和hashCode方法必须兼容,如:equals方法判断的是用户的名字 ...

  4. Java 中的 HashSet,内部是如何工作的?

    HashSet 的内部采用 HashMap 来实现.由于 Map 需要 key 和 value,所以 所有 key 的都有一个默认 value.类似于 HashMap,HashSet 不允许重复的 k ...

  5. java中使用hashSet的特性,判断数组是否有重复值

    public static boolean cheakRepeat(int[] array){ HashSet<Integer> hashSet = new HashSet<Inte ...

  6. java 中遍历hashmap 和hashset 的方法

    一.java中遍历hashmap:    for (Map.Entry<String, Integer> entry : tempMap.entrySet()) {     String ...

  7. Java中如何克隆集合——ArrayList和HashSet深拷贝

    编程人员经常误用各个集合类提供的拷贝构造函数作为克隆List,Set,ArrayList,HashSet或者其他集合实现的方法.需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味 ...

  8. java中HashSet详解(转)

    HashSet 的实现 对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSe ...

  9. java中HashSet详解

    HashSet 的实现 对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSe ...

  10. java集合(4)- java中HashSet详解

    HashSet 的实现 对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSe ...

随机推荐

  1. git pull发现有ahead of xx commits问题如何解决

    git pull 的时候发现有提示你ahead of xx commits 这个时候怎么办呢? 直接一句话定位到远程最新分支 git reset --hard origin/分支名称

  2. (系列十二)Vue3+.Net8实现用户登录(超详细登录文档)

    说明 该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发). 该系统文章,我会尽量说的非常详细,做到不管新手.老手都能看懂. 说明:OverallAuth2 ...

  3. apisix问题记录

    负载均衡 可以给 rest api(9080)做负载均衡 不可以给dashboard做负载均衡,否则会出现闪退,dashboard之间的token并不是通用的 路由导出 openapi 路由导出ope ...

  4. Personal Wiki

    What is a PersonalWiki? It's like WardsWiki, but it's yours. It can be: a free-form database a Perso ...

  5. Mybatis【7】-- Mybatis如何知道增删改是否成功执行?

    代码直接放在Github仓库[https://github.com/Damaer/Mybatis-Learning/tree/master/mybatis-05-CURD ] 需要声明的是:此Myba ...

  6. 从Delphi到Lazarus——在Lazarus中使用ActiveX控件(导入类型库)

    0.前言 Lazarus的设计目标是应用Free Pascal,所以所有凡是Free Pascal能运行的平台,Lazarus都可以运行.通俗地说就是Lazarus追求的是跨平台编程,致力于" ...

  7. C++ Builder 开发64程序 使用AnsiString的ToInt和ToDouble会内存泄漏

    AnsiString str="adsfaga"; try { int v=str.ToInt(); } catch(...) { } 上面的代码,在C++ Builder 10 ...

  8. GooseFS 统一命名空间 | 加速存储业务访问

    01 前言 ​ GooseFS是 腾讯云存储团队推出的分布式缓存方案,主要针对需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. 统一命名空间是GooseFS提供的透明命名 ...

  9. vue3 在给路由跳转增加动画之后,跳转时页面会出现上下抖动的问题

    这个问题需要分两个步骤解决: 抖动的页面有多个多根节点 增加离开过渡的css样式 v-leave-to: {display: none} 解决步骤1 (抖动的页面有多个多根节点) 我在为路由跳转增加了 ...

  10. 有关IOS内存读写冲突

    有关IOS内存读写冲突 在写内存相关代码时,获取已使用内存代码中报错 let hostPort: mach_port_t = mach_host_self() var host_size = mach ...