27.5 Java集合之Set学习(基本概念,存储原理,性能测试)

news2024/11/17 3:34:47

文章目录

  • 1.Set接口
    • 1.1 Set的特性是什么?
  • 2.具体实现
  • 2.1 HashSet
      • 2.1.1 存储原理
      • 2.1.2 性能测试
    • 2.2 TreeSet
      • 2.2.1 存储原理
      • 2.2.2 性能测试
    • 2.3 EnumSet(了解即可)
      • 2.3.1 存储原理
    • 2.4 LinkedHashSet
    • 2.4.1 存储原理
    • 2.4.2 性能测试
      • 2.4.3 代码地址

1.Set接口

在这里插入图片描述

在正式学习Set接口之前,我们得先复习一下上面的图片。
我们知道Set接口继承于Collection接口,但是他又有自己的特点,下面我们看一下Set接口不同于Collection的特殊方法定义:

看完源码后,没发现Set中有特殊的方法定义。

现在我们思考一下,为何没有呢? 其实这个问题我们可以思考一下Collection中定义的方法是否能满足Set特性?

1.1 Set的特性是什么?

Set的最大的特性就是存储不重复的元素。
那么我们只需要保证使用Set的add()时具有排重逻辑。 其他的和Collection无异。

注意:我个人认为无序并不是Set的主要特性,无序是Hash存储的特性。

2.具体实现

老规矩,看图复习,然后根据具体的类进行学习。
在这里插入图片描述

上面的图片中我们可以看出,实现Set的实现可能有:

HashSet, TreeSet, EnumSet, LinkedHashSet

嗯? 这不是和HashMap, TreeMap, EnumMap,LinkedHashMap有异曲同工之妙吗?

别着急,更神奇的还在后头!!

2.1 HashSet

通过查阅源码,我们发现了,HashSet中维护的存储结构是HashMap。

2.1.1 存储原理

当进行add(E e)的时候,就会向map中put(e,Object常量),如果返回的是null,则表示添加成功,如果返回的不是null,则表示Map中已经存在键值对,添加失败。
当进行contains(Object o)的时候,调用的也是Map的containsKey(Object o);

所以HashSet的存储原理就是利用HashMap的键不可重复的特性进行实现的。
由于HashSet借助了HashMap进行存储,所以对其进行存储时无法保证有序存储。

2.1.2 性能测试

//完整代码存放在git仓库中,地址在文章底部
public static void main(String[] args) {
    Set<Integer> set = new HashSet<>();
    long start = System.currentTimeMillis();
    for(int i=0;i<10000000;i++){
        set.add(i);
    }
    System.out.println("存储耗时: "+(System.currentTimeMillis()-start)+" ms");
    long start2 = System.currentTimeMillis();
    for(int i=0;i<10000000;i++){
       boolean c = set.contains(i);
    }
    System.out.println("查询耗时: "+(System.currentTimeMillis()-start2)+" ms");
}

在这里插入图片描述

2.2 TreeSet

通过查阅源码,我们可以知道,TreeSet中维护的存储结构是NavigableMap接口,默认实现是TreeMap,
简单来说,TreeSet也是借助TreeMap来进行存储的,TreeMap是Map的有序实现,它会根据键的顺序将元素组织为一个搜索树。

2.2.1 存储原理

当进行add(E e)的时候,就会向map中put(e,Object常量),如果返回的是null,则表示添加成功,如果返回的不是null,则表示Map中已经存在键值对,添加失败。
当进行contains(Object o)的时候,调用的也是Map的containsKey(Object o);

所以TreeSet的存储原理就是利用TreeMap的键不可重复的特性进行实现的。
由于TreeSet借助了TreeMap进行存储,所以对其进行存储可以保证存储的顺序。

2.2.2 性能测试

//完整代码存放在git仓库中,地址在文章底部
public static void main(String[] args) {
    TreeSet<Integer> set = new TreeSet<>();
    long start = System.currentTimeMillis();
    for(int i=100;i>0;i--){
        set.add(i);
    }
    System.out.println("存储耗时: "+(System.currentTimeMillis()-start)+" ms");
    long start2 = System.currentTimeMillis();
    for(int i=0;i<100;i++){
        boolean c = set.contains(i);
    }
    System.out.println("查询耗时: "+(System.currentTimeMillis()-start2)+" ms");

    for(Integer i:set){
        System.out.print(i+" ");
    }
}

在这里插入图片描述

可以看到在TreeSet中,存储Integer是自然升序排序的。

2.3 EnumSet(了解即可)

它是一个继承了AbstractSeet的抽象类。
其中一个具体的实现是:RegularEnumSet 它是Set的常规实现, EnumSet的实现并不是一个公共的类,所以它不能作为公共API直接使用。
它是用来存储枚举的Set集合。这个类好像只能存,不能取。

2.3.1 存储原理

我们以RegularEnum为例子进行存储原理的学习。
通过阅读add源码, 我们发现其中关键在于使用了elements这个变量来记录传入的值。

//add操作实际是用位运算,
//将这个long值对应你传入的枚举值的下标的那个bit位改成1,
//比如我传入的是IdentityEnu.DRIVER, 对应的ordinal是1,
//则是将elements的bit位中的第2位改成1,
public boolean add(E e) {
    typeCheck(e);
    long oldElements = elements;
    elements |= (1L << ((Enum<?>)e).ordinal());
    return elements != oldElements;
}
//contains操作就是检查指定位的是否为0来判断
public boolean contains(Object e) {
    if (e == null)
        return false;
    Class<?> eClass = e.getClass();
    if (eClass != elementType && eClass.getSuperclass() != elementType)
        return false;

    return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
}

比较特殊的一点是,elements用的是long,它只有64位,所以,它存储的枚举类的值不能超过64.

2.4 LinkedHashSet

这个类继承的HashSet,所以它的存储结构仍然是HashMap。查看LinkedHashSet的源码时,你也许会这么想,但是,真的是这样的吗?
但是我们需要实事求是,看下源码到底是怎么运行的:

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

看到这里,我们意识到猜错了,其实LinkedHashSet的存储结构是LinkedHashMap!!
LinkedHashMap是对HashMap的一种增强:
它会记住插入元素的顺序,这样在使用迭代器进行遍历的时候,遍历元素则是有序的。
LinkedHashMap通过重写newNode方法,让其在新创建Node的时候将其插入顺序通过双向链表结构记录下来。

transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;

2.4.1 存储原理

当进行add(E e)的时候,就会向map中put(e,Object常量),如果返回的是null,则表示添加成功,如果返回的不是null,则表示Map中已经存在键值对,添加失败。
当进行contains(Object o)的时候,调用的也是Map的containsKey(Object o);

所以LinkedHashSet的存储原理就是利用LinkedHashMap的键不可重复的特性进行实现的。
由于LinkedHashSet借助了LinkedHashMap进行存储,所以对其进行存储可以保证存储的顺序。

2.4.2 性能测试

public static void main(String[] args) {

    LinkedHashSet<Integer> set = new LinkedHashSet<>();
    long start = System.currentTimeMillis();
    for(int i=100;i>0;i--){
        set.add(i);
    }
    System.out.println("存储耗时: "+(System.currentTimeMillis()-start)+" ms");
    long start2 = System.currentTimeMillis();
    for(int i=0;i<100;i++){
        boolean c = set.contains(i);
    }
    System.out.println("查询耗时: "+(System.currentTimeMillis()-start2)+" ms");

    for(Integer i:set){
        System.out.print(i+" ");
    }
}

在这里插入图片描述

2.4.3 代码地址

Java基础学习/src/main/java/Progress/exa27_5 · 严家豆/Study - 码云 - 开源中国 (gitee.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Gitee】上传本地项目到 Gitee 仓库(入门篇)

本文主要介绍上传本地项目到 Gitee 仓库的过程&#xff0c;可以说是一个比较傻瓜的教材吧&#xff0c;从0开始&#xff0c;祝大家都能一次成功~~~ 一、前期准备 1. 配置 Gitte 创建 Gitte 账号&#xff0c;绑定好邮箱&#xff0c;并创建一个空仓库 。创建账号绑定邮箱过程这部…

【信号检测】基于小波变换的信号趋势检测和分离研究附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

双十一好物推荐:2022年好用的数码好物分享

一年一度的双十一尽在眼前&#xff0c;因为双十一的优惠力度是一年中最大的一次&#xff0c;所以许多人都想着直接一年屯一次&#xff0c;一次屯一年的理念&#xff0c;那么作为资深剁手党的我来说&#xff0c;对比于选购双十一好物来说我还是比较有心得的&#xff0c;下面让我…

机器视觉之工业摄像机知识点(一)

本文主要记录一些基础的工业摄像机的一些简要知识点。我也是根据我觉得比较重要的来记录。作为一位算法工程师&#xff0c;其实是有两条路来走&#xff0c;即技术专家以及技术经理。这两个实际是不同的职业方向。如果你不擅于与外部沟通交流&#xff0c;并且具备非常强的科研和…

基于OpenHarmony的ArkUI框架进阶对于高性能容器类和持久化和原子化的运用

文章目录高性能容器类Badge原子化服务代码简析表达式持久化高性能容器类 顾名思义&#xff0c;容器类是一个存储类&#xff0c;用于存储各种数据类型的元素&#xff0c;并提供一系列处理数据元素的方法。ArkUI开发框架提供了两种类型的容器类&#xff0c;线性和非线性。这些容…

【机器学习】求矩阵的-1/2次方的方法

目录 一、背景描述 二、D^(-1/2)的理论基础 三、代码实现 四、总结 一、背景描述 今天在看如下论文的时候&#xff1a; 态势感知图卷积网络在电力系统连锁故障中的应用-机器学习文档类资源-CSDN文库https://download.csdn.net/download/mzy20010420/86745616?spm1001.20…

Rust之常用集合(一):向量(vector)

开发环境 Windows 10Rust 1.64.0VS Code 1.72.2 项目工程 这里继续沿用上次工程rust-demo 常用集合 Rust的标准库包括许多非常有用的数据结构&#xff0c;称为集合。大多数其他数据类型表示一个特定的值&#xff0c;但是集合可以包含多个值。与内置数组和元组类型不同&…

2022年数维杯数学建模A题银行效率评价与破产成因分析求解全过程文档及程序

2022年数维杯数学建模 A题 银行效率评价与破产成因分析 原题再现&#xff1a; 银行在国家经济社会发展过程中扮演者重要的决策&#xff0c;银行的破产会对企业和个人造成众多不利的影响。相比国内的银行&#xff0c;国际银行的倒闭频次更高&#xff0c;因此国际银行倒闭原因的…

一小时教你轻松学会使用Java 整合 Easy Excel 操作 Excel 文件

文章目录一、Apache POI简介二、POI操作Excel构建maven项目导入依赖使用POI实现基本写操作使用POI实现大数据量写操作使用POI实现基本读操作使用POI读取不同类型的数据三、Easy Excel简介构建maven项目导入依赖实现写操作实现读操作目前市面上比较流行的操作Excel 文件工具大致…

【前端】vue阶段案例:vue-router使用流程

文章目录目标步骤1.配置映射关系2.导入路由并注册3.完成首页App.vue可能出现的问题&#xff1a;Component name "About" should always be multi-word参考目标 点击首页&#xff0c;则url变为/home&#xff0c;且下面显示的组件是Home组件点击关于&#xff0c;则url变…

更易用的OceanBase|生态工具征文大赛正式开启!

OceanBase 一直在思考&#xff0c;什么样的数据库对用户而言更易用&#xff1f; 更易用&#xff0c;除了功能完善、性能优秀、运行稳定的数据库系统&#xff0c;丰富多样的生态工具也必不可少。 作为一款完全自主研发的原生分布式数据库&#xff0c;OceanBase 的生态工具经历…

Java图片或视频生成GIF动图,发送微信

目录前言GIF简介代码生成图片合成GIF自定义GIF动图视频生成GIF发送微信小结前言 别人的博客文章中有动态显示这是怎么做到的呢&#xff1f;别人的微信发送的表情动态为什么是自己鬼畜视频&#xff1f;这些都是别人做到的&#xff0c;本文就是让自己也可以做到以上的事情&#…

Java基于springboot+vue的图书馆网上图书借阅系统 nodejs前后端分离

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括网上图书借阅系统的网络应用&#xff0c;在外国网上图书借阅系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。网上图书借阅系统具有网上图书信息管…

HTML小游戏3—— 机器人总动员(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 风趣幽默的前端学习课程&#xff1a;&#x1f449;28个案例趣学前端&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且实用的计算机相关知…

北京化工大学数据结构2022/10/27作业 题解

目录 问题 A: 二叉树的性质 问题 B: 二叉树的节点 问题 C: 满二叉树 问题 D: 完全二叉树的节点序号 -----------------------------------分割线------------------------------------------ 问题 E: 二叉树的深度 问题 F: 数据结构作业04 -- 二叉树的输入 递归版 迭代版…

【第一阶段:java基础】第4章:java控制结构

本系列博客是韩顺平老师java基础课的课程笔记 韩顺平P103-P1551. 顺序2. 分支3. 循环4. 跳转5. 编程思想1. 顺序 程序从上至下逐行执行&#xff0c;中间没有任何判断和跳转 2. 分支 单分支if双分支if-else多分支if - else if … - else嵌套分支&#xff1a;建议嵌套最好不要…

【水果派不吃灰】Raspberry Pi树莓派Linux系统下替换国内apt软件更新源

目录1. 前言2. 备份原始配置文件3. 修改原始文件3.1 软件更新源3.2 系统更新源4. 更新4.1 sudo apt-get update 更新软件源列表4.1 sudo apt-get upgrade 更新软件版本(时间会久点)4.1 sudo apt-get dist-upgrade4.1 sudo rpi-update 内核版本&#xff08;尽量不更新&#xff0…

Web前端 | JavaScript(BOM编程和JSON)

✅作者简介&#xff1a;一位材料转码农的选手&#xff0c;希望一起努力&#xff0c;一起进步&#xff01; &#x1f4c3;个人主页&#xff1a;每天都要敲代码的个人主页 &#x1f525;系列专栏&#xff1a;Web前端 &#x1f4ac;推荐一款模拟面试、刷题神器&#xff0c;从基础到…

Matplotlib | 世界足球俱乐部排名可视化

文章目录&#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. 示例数据&#x1f3f3;️‍&#x1f308; 3. 画布设置&#x1f3f3;️‍&#x1f308; 4. 画布区域主题分配&#x1f3f3;️‍&#x1f308; 5. 添加数据散点&#x1f3f3;️‍&#x1f…

Python学习六(进程)

1.简介 多进程在使用中是非常常见的&#xff0c;如果对多进程比较陌生&#xff0c;那可以换个说法&#xff0c;叫多任务。 那什么叫做多任务呢&#xff1f;顾名思义就是多个任务。比如我们使用电脑时&#xff0c;打开浏览器&#xff0c;是一个任务、打开视频&#xff0c;是一个…