【JAVA语言-第16话】集合框架(三)——Set、HashSet、LinkedHashSet、TreeSet集合的详细解析

本文主要是介绍【JAVA语言-第16话】集合框架(三)——Set、HashSet、LinkedHashSet、TreeSet集合的详细解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

Set集合

1.1 概述 

1.2 特点

1.3 HashSet集合

1.3.1 概述 

1.3.2 哈希表 

1.3.3 哈希值

1.3.4 练习

1.3.5 HashSet存储自定义类型元素

1.4 LinkedHashSet集合

1.4.1 概述

1.4.2 特点

1.4.3 练习

1.5 TreeSet集合

1.5.1 概述

1.5.2 练习

1.6 HashSet、LinkedHashSet、TreeSet 的异同点


Set集合

1.1 概述 

         java.util.Set:是一个接口,和List一样,也是继承自Collection,常用的实现类有TreeSet、HashSet,LinkedHashSet。

1.2 特点

  • 存取无序,存储的顺便和取出的数据不一定一致。 
  • 没有索引,不能通过索引操作元素。
  • 不可以存储重复的元素。相同元素的判断:哈希值相同,内容相同。

1.3 HashSet集合

1.3.1 概述 

         java.util.HashSet:在Java中,HashSet是一种基于哈希表的集合实现。它继承自AbstractSet类并实现了Set接口。HashSet类在内部使用哈希表来存储元素,并且不保证元素的顺序。它允许存储唯一的元素,不允许重复。HashSet提供了常量时间的查找、插入和删除操作,因此可以在大多数情况下提供高效的性能。 

1.3.2 哈希表 

        在jdk1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一个哈希值的元素都存储在一个链表中,但是当位于一个链表中的元素较多,即哈希值相等的元素较多时,通过Key值依次查找的效率较低;所以在jdk1.8中,哈希表存储采用数组+链表/红黑树实现,当链表的长度超过8时,将链表转换为红黑树,这样大大减少了查找时间。

1.3.3 哈希值

        是一个十进制整数,由系统随机给出(就是对象的地址,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址),在Object类中有一个方法,可以获取对象的哈希值。

public native int hashCode():返回该对象的哈希码值。

        

toString方法的源码:内部就是调用hashCode()方法
        public String toString(){
            return getClass().getName() + "@" + Integer.toHaxString(hashCode());
        }

1.3.4 练习

package com.zhy.coll;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class TestHashSet {public static void main(String[] args) {//多态,接口引用 指向 实现类对象Set<Integer> set = new HashSet<>();//往Set集合中添加元素,Set和List一样继承了Collection,所有两个类操作元素有着相似的方法set.add(10);set.add(20);set.add(30);//猜猜:这个元素能不能存储进Set集合?set.add(10);//打印Set集合印证一下//输出:初始化Set集合:[20, 10, 30]//明明添加了4个元素,但是最终Set集合中只有三个,这就是Set区别于List的地方,前者是不允许存储重复数据的//且存储是10,20,30,但是输出且不是按照存储数据打印,这也是Set区别于List的地方,前者是无序的System.out.println("初始化Set集合:" + set);//遍历集合,可以使用迭代器或者增强for循环//1.使用迭代器Iterator<Integer> iterator = set.iterator();while(iterator.hasNext()){Integer integer = iterator.next();System.out.print(integer + " ");}//2.使用增强forfor(Integer integer : set){System.out.print(integer + " ");}}
}

1.3.5 HashSet存储自定义类型元素

        Set集合保证元素唯一:(String,Integer,...Student,Person),自定义的类如果想要使用Set集合存储,必须重写hashCode方法和equals方法,才能过滤掉重复的数据。

 源代码:

package com.zhy.coll;import java.util.Objects;public class Persion {private String name;private int age;public Persion() {}public Persion(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}/*** 自定义类型,重写equals方法*  比较规则:name 和 age 内容都相同,返回true,否则,返回false* @param o* @return*/@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Persion persion = (Persion) o;if (age != persion.age) return false;return name != null ? name.equals(persion.name) : persion.name == null;}/*** 获取对象的hashCode,必须和equals一起重写* @return*/@Overridepublic int hashCode() {int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}/*** 重写toString,返回对象的内容,如果不重写,默认对象的地址* @return*/@Overridepublic String toString() {return "Persion{" +"name='" + name + '\'' +", age=" + age +'}';}
}
package com.zhy.coll;import java.util.HashSet;public class TestPersion {public static void main(String[] args) {//使用HashSet存储String类型的数据//排除重复元素规则:首先比较两个值的hashCode是否相同,其次比较两个值的内容是否相同//如果两种情况都相同,HashSet会判定为这两个值是同一个元素,只会存储一个//如果hashCode相同,内容不相同,那么会以链表的形式存储在一个hashCode下面HashSet<String> set1 = new HashSet<>();String str1 = new String("abc");String str2 = new String("abc");String str3 = new String("重地");String str4 = new String("通话");System.out.println("str1的hashCode:" + str1.hashCode());System.out.println("str2的hashCode:" + str2.hashCode());System.out.println("str3的hashCode:" + str3.hashCode());System.out.println("str4的hashCode:" + str4.hashCode());System.out.println("str1 和 str2是否是同一个元素:" + (str1.hashCode() == str2.hashCode() && str1.equals(str2)));System.out.println("str3 和 str4是否是同一个元素:" + (str3.hashCode() == str4.hashCode() && str3.equals(str4)));set1.add(str1);set1.add(str2);set1.add(str3);set1.add(str4);System.out.println("初始化String类型的Set集合:" + set1);System.out.println("========================================================");//使用HashSet存储自定义类型Persion的数据,为了保证Set集合不重复存储的特性,自定义类型必须重写hashCode和equals方法//比较规则:// 根据name和age获取唯一的hashCode值,然后在比较两个对象的名称+年龄是否相同// 二者都相同,代表同一个对象,不重复存储HashSet<Persion> set2 = new HashSet<>();Persion p1 = new Persion("张三",18);Persion p2 = new Persion("张三",18);Persion p3 = new Persion("李思",28);System.out.println("p1的hashCode:" + p1.hashCode());System.out.println("p2的hashCode:" + p2.hashCode());System.out.println("p3的hashCode:" + p3.hashCode());System.out.println("p1 和 p2是否是同一个元素:" + (p1.hashCode() == p2.hashCode() && p1.equals(p2)));set2.add(p1);set2.add(p2);set2.add(p3);System.out.println("初始化Persion类型的Set集合:" + set2);}
}

 输出结果:

1.4 LinkedHashSet集合

1.4.1 概述

        java.util.LinkedHashSet:在Java中,LinkedHashSet是一种集合类,它是HashSet的子类。它继承了HashSet的特性,同时还保持了元素的插入顺序。与HashSet不同的是,LinkedHashSet使用链表来维护集合中元素的顺序。

1.4.2 特点

        底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序。

1.4.3 练习

源代码:

package com.zhy.coll;import java.util.Iterator;
import java.util.LinkedHashSet;public class TestLinkedHashSet {public static void main(String[] args) {//创建集合,存储Integer类型的数据LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<Integer>();//往集合中添加数据linkedHashSet.add(10);linkedHashSet.add(20);linkedHashSet.add(30);linkedHashSet.add(40);linkedHashSet.add(20);//遍历集合,迭代器或者增强forSystem.out.print("使用迭代器遍历集合:");Iterator<Integer> iterator = linkedHashSet.iterator();while (iterator.hasNext()){Integer integer = iterator.next();System.out.print(integer + " ");}}
}

输出结果:      

        查看集合的数据,不仅遍历的顺序和添加的顺序一致,还过滤掉了重复数据。

 

1.5 TreeSet集合

1.5.1 概述

        java.util.TreeSet:在Java中,TreeSet是一个实现了Set接口的有序集合。它是通过红黑树数据结构实现的,可以保证元素按照自然排序或者通过Comparator进行排序。TreeSet不允许重复元素,并且可以高效地进行插入、删除和查找操作。由于TreeSet是有序的,因此它提供了一些额外的方法,如获取最小元素、获取最大元素、获取小于等于某个值的最大元素等。

1.5.2 练习

源代码: 

package com.zhy.coll;import java.util.TreeSet;public class TestTreeSet {public static void main(String[] args) {TreeSet<Integer> treeSet = new TreeSet<>();treeSet.add(12);treeSet.add(98);treeSet.add(10);System.out.println("初始化treeSet集合:" + treeSet);Integer first = treeSet.first();System.out.println("获取集合中的第一个元素:" + first);Integer integer = treeSet.pollLast();System.out.println("移除集合中的最后一个元素:" + integer);System.out.print("使用增强for遍历集合:");for (Integer i : treeSet){System.out.print(i + " ");}}
}

输出结果: 

1.6 HashSet、LinkedHashSet、TreeSet 的异同点

        HashSet、LinkedHashSet和TreeSet是Java中集合框架中Set集合的三个实现类,它们之间有一些异同点。

数据结构:

  • HashSet是基于哈希表实现的集合,它使用哈希函数来确定元素的存储位置。
  • LinkedHashSet是HashSet的子类,它在哈希表的基础上使用链表来维护元素的插入顺序。
  • TreeSet是基于红黑树实现的集合,它能够自动将元素按照自然顺序或自定义的比较器顺序进行排序。

 插入顺序:

  • HashSet不保证元素的插入顺序,元素在集合中的位置是根据哈希函数计算得到的。
  • LinkedHashSet保持元素的插入顺序,即元素按照插入的顺序进行迭代。
  • TreeSet会根据元素的排序规则对元素进行排序,并且在遍历时按照排序后的顺序进行迭代。

排序: 

  • HashSet和LinkedHashSet不对元素进行排序,元素的顺序是根据哈希函数计算得到的。
  • TreeSet会根据元素的自然顺序或自定义的比较器顺序对元素进行排序。

性能: 

  • HashSet的性能通常比较好,它提供了O(1)的常数时间复杂度的插入、删除和查找操作。
  • LinkedHashSet的插入、删除和查找操作的性能稍微低于HashSet,因为它还需要维护插入顺序。
  • TreeSet提供了O(log n)的时间复杂度的插入、删除和查找操作,它的性能较HashSet和LinkedHashSet要低。

        总而言之,HashSet适用于需要快速插入、删除和查找操作的场景;LinkedHashSet适用于需要保持插入顺序的场景;TreeSet适用于需要对元素进行排序的场景。

这篇关于【JAVA语言-第16话】集合框架(三)——Set、HashSet、LinkedHashSet、TreeSet集合的详细解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658364

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏