我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java HashSet怎么添加遍历元素

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java HashSet怎么添加遍历元素

本篇内容主要讲解“Java HashSet怎么添加遍历元素”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java HashSet怎么添加遍历元素”吧!

HashSet 类图

Java HashSet怎么添加遍历元素

HashSet 简单说明

HashSet 实现了 Set 接口

HashSet 底层实际上是由 HashMap 实现的

public HashSet() {        map = new HashMap<>();}

可以存放 null,但是只能有一个 null

HashSet 不保证元素是有序的(即不保证存放元素的顺序和取出元素的顺序一致),取决于 hash 后,再确定索引的结果

不能有重复的元素

HashSet 底层机制说明

HashSet 底层是 HashMapHashMap 底层是 数组 + 链表 + 红黑树

模拟数组+链表的结构

Java HashSet怎么添加遍历元素

public class HashSetStructureMain {    public static void main(String[] args) {        // 模拟一个 HashSet(HashMap) 的底层结构        // 1. 创建一个数组,数组的类型为 Node[]        // 2. 有些地方直接把 Node[] 数组称为 表        Node[] table = new Node[16];        System.out.println(table);        // 3. 创建节点        Node john = new Node("john", null);        table[2] = jhon; // 把节点 john 放在数组索引为 2 的位置        Node jack = new Node("jack", null);        jhon.next = jack; // 将 jack 挂载到 jhon 的后面        Node rose = new Node("rose", null);        jack.next = rose; // 将 rose 挂载到 jack 的后面        Node lucy = new Node("lucy", null);        table[3] = lucy; // 将 lucy 放在数组索引为 3 的位置        System.out.println(table);    }}// 节点类 存储数据,可以指向下一个节点,从而形成链表class Node{    Object item; // 存放数据    Node next; // 指向下一个节点    public Node(Object item, Node next){        this.item = item;        this.next = next;    }}

HashSet 添加元素底层机制

HashSet 添加元素的底层实现

HashSet 底层是 HashMap

当添加一个元素时,会先得到 待添加元素的 hash 值,然后将其转换成一个 索引值

查询存储数据表(Node 数组) table,看当前 待添加元素 所对应的 索引值 的位置是否已经存放了 其它元素

如果当前 索引值 所对应的的位置不存在 其它元素,就将当前 待添加元素 放到这个 索引值 所对应的的位置

如果当前 索引值 所对应的位置存在 其它元素,就调用 待添加元素.equals(已存在元素) 比较,结果为 true,则放弃添加;结果为 false,则将 待添加元素 放到 已存在元素 的后面(已存在元素.next = 待添加元素)

HashSet 扩容机制

HashSet 的底层是 HashMap,第一次添加元素时,table 数组扩容到 cap = 16threshold(临界值) = cap * loadFactor(加载因子 0.75) = 12

如果 table 数组使用到了临界值 12,就会扩容到 cap * 2 = 32,新的临界值就是 32 * 0.75 = 24,以此类推

在 Java8 中,如果一条链表上的元素个数 到达 TREEIFY_THRESHOLD(默认是 8),并且 table 的大小 >= MIN_TREEIFY_CAPACITY(默认是 64),就会进行 树化(红黑树)

判断是否扩容是根据 ++size > threshold,即是否扩容,是根据 HashMap 所存的元素个数(size)是否超过临界值,而不是根据 table.length() 是否超过临界值

HashSet 添加元素源码

public class HashSetSourceMain {    public static void main(String[] args) {        HashSet hashSet = new HashSet();        hashSet.add("java");        hashSet.add("php");        hashSet.add("java");        System.out.println("set = " + hashSet);        // 源码分析        // 1. 执行 HashSet()                // 2. 执行 add()                // 3. 执行 put()        // hash(key) 得到 key(待存元素) 对应的hash值,并不等于 hashcode()        // 算法是 h = key.hashCode()) ^ (h >>> 16                // 4. 执行 putVal()        // 定义的辅助变量:Node<K,V>[] tab; Node<K,V> p; int n, i;        // table 是 HashMap 的一个属性,初始化为 null;transient Node<K,V>[] table;        // resize() 方法,为 table 数组指定容量        // p = tab[i = (n - 1) & hash] 计算 key的hash值所对应的 table 中的索引位置,将索引位置对应的 Node 赋给 p            }}

HashSet 遍历元素底层机制

HashSet 遍历元素底层机制

HashSet 的底层是 HashMapHashSet 的迭代器也是借由 HashMap 来实现的

HashSet.iterator() 实际上是去调用 HashMap 的 KeySet().iterator()

public Iterator<E> iterator() {    return map.keySet().iterator();}

KeySet() 方法返回一个 KeySet 对象,而 KeySet 是 HashMap 的一个内部类

public Set<K> keySet() {    Set<K> ks = keySet;    if (ks == null) {        ks = new KeySet();        keySet = ks;    }    return ks;}

KeySet().iterator() 方法返回一个 KeyIterator 对象,KeyIterator 是 HashMap 的一个内部类

public final Iterator<K> iterator()     { return new KeyIterator(); }

KeyIterator 继承了 HashIterator(HashMap的内部类) 类,并实现了 Iterator 接口,即 KeyIteratorHashIterator 才是真正实现 迭代器 的类

final class KeyIterator extends HashIterator    implements Iterator<K> {    public final K next() { return nextNode().key; }}

当执行完 Iterator iterator = HashSet.iterator; 之后,此时的 iterator 对象中已经存储了一个元素节点

  • 怎么做到的?

  • 回到第 4 步,KeySet().iterator() 方法返回一个 KeyIterator 对象

  • new KeyIterator() 调用 KeyIterator 的无参构造器

  • 在这之前,会先调用其父类 HashIterator 的无参构造器

  • 因此,分析 HashIterator 的无参构造器就知道发生了什么

  • nextcurrentindex 都是 HashIterator 的属性

  • Node<K,V>[] t = table; 先把 Node 数组 talbe 赋给 t

  • current = next = null; currentnext 都置为 null

  • index = 0; index 置为 0

  • do {} while (index < t.length && (next = t[index++]) == null); 这个 do-while 会在 table 中遍历 Node 结点

  • 一旦 (next = t[index++]) == null 不成立 时,就说明找到了一个 table 中的 Node 结点

  • 将这个节点赋给 next,并退出当前 do-while 循环

  • 此时 Iterator iterator = HashSet.iterator; 就执行完了

  • 当前 iterator 的运行类型其实是 HashIterator,而 HashIterator 的 next 中存储着从 table 中遍历出来的一个 Node 结点

执行 iterator.hasNext

此时的 next 存储着一个 Node,所以并不为 null,返回 true

public final boolean hasNext() {    return next != null;}

执行 iterator.next()

I.Node<K,V> e = next; 把当前存储着 Node 结点的 next 赋值给了 e

II.(next = (current = e).next) == null 判断当前结点的下一个结点是否为 null

  • (a). 如果当前结点的下一个结点为 null,就执行 do {} while (index < t.length && (next = t[index++]) == null);,在 table 数组中遍历,寻找 table 数组中的下一个 Node 并赋值给 next

  • (b). 如果当前结点的下一个结点不为 null,就将当前结点的下一个结点赋值给 next,并且此刻不会去 table 数组中遍历下一个 Node 结点

III.将找到的结点 e 返回

IV.之后每次执行 iterator.next() 都像 (a)(b) 那样去判断遍历,直到遍历完成

HashSet 遍历元素源码

public class HashSetSourceMain {    public static void main(String[] args) {        HashSet hashSet = new HashSet();        hashSet.add("java");        hashSet.add("php");        hashSet.add("java");        System.out.println("set = " + hashSet);        // HashSet 迭代器实现原理        // HashSet 底层是 HashMap,HashMap 底层是 数组 + 链表 + 红黑树        // HashSet 本身没有实现迭代器,而是借由 HashMap 来实现的        // 1. hashSet.iterator() 实际上是去调用 HashMap 的 keySet().iterator()                // 2. KeySet() 方法返回一个 KeySet 对象,而 KeySet 是 HashMap 的一个内部类                // 3. KeySet().iterator() 方法返回一个 KeyIterator 对象,KeyIterator 是 HashMap的一个内部类                // 4. KeyIterator 继承了 HashIterator(HashMap的内部类) 类,并实现了 Iterator 接口        // 即 KeyIterator、HashIterator 才是真正实现 迭代器的类                // 5. 当执行完 Iterator iterator = hashSet.iterator(); 后        // 此时的 iterator 对象中已经存储了一个元素节点        // 怎么做到的?        // 回到第 3 步,KeySet().iterator() 方法返回一个 KeyIterator 对象        // new KeyIterator() 调用 KeyIterator 的无参构造器        // 在这之前,会先调用 KeyIterator 父类 HashIterator 的无参构造器        // 因此分析 HashIterator 的无参构造器就知道发生了什么                // 5.0 next, current, index 都是 HashIterator 的属性        // 5.1 Node<K,V>[] t = table; 先把 Node 数组 table 赋给 t        // 5.2 current = next = null; 把 current 和 next 都置为 null        // 5.3 index = 0; index 置为 0        // 5.4 do {} while (index < t.length && (next = t[index++]) == null);        // 这个 do{} while 循环会在 table 中 遍历 Node节点        // 一旦 (next = t[index++]) == null 不成立时,就说明找到了一个 table 中的节点        // 将这个节点赋给 next,并退出当前 do while循环        // 此时 Iterator iterator = hashSet.iterator(); 就执行完了        // 当前 iterator 的运行类型其实是 HashIterator,而 HashIterator 的 next 中存储着从 table 中遍历出来的一个 Node节点        // 6. 执行 iterator.hasNext()                // 6.1 此时的 next 存储着一个 Node,所以并不为 null,返回 true        // 7. 执行 iterator.next(),其实是去执行 HashIterator 的 nextNode()                // 7.1 Node<K,V> e = next; 把当前存储着 Node 节点的 next 赋值给了 e        // 7.2 (next = (current = e).next) == null        // 判断当前节点的下一个节点是否为 null        // a. 如果当前节点的下一个节点为 null        // 就执行 do {} while (index < t.length && (next = t[index++]) == null);        // 再 table 数组中 遍历,寻找 table 数组中的下一个 Node 并赋值给 next        // b. 如果当前节点的下一个节点不为 null        // 就将当前节点的下一个节点赋值给 next,并且此刻不会去 table 数组中遍历下一个 Node 节点        // 7.3 将找到的节点 e 返回        // 7.4 之后每次执行 iterator.next(),都像 a、b 那样去判断遍历,直到遍历完成        Iterator iterator = hashSet.iterator();        while (iterator.hasNext()) {            Object next =  iterator.next();            System.out.println(next);        }    }}

到此,相信大家对“Java HashSet怎么添加遍历元素”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java HashSet怎么添加遍历元素

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java HashSet怎么添加遍历元素

本篇内容主要讲解“Java HashSet怎么添加遍历元素”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java HashSet怎么添加遍历元素”吧!HashSet 类图HashSet 简单说明
2023-07-02

java数组怎么遍历全部的元素

这篇文章主要介绍了java数组怎么遍历全部的元素的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java数组怎么遍历全部的元素文章都会有所收获,下面我们一起来看看吧。说明1、分别从数组中获取每一个元素,即遍历。在
2023-06-30

java怎么往数组添加元素

在Java中,可以使用数组的拷贝来实现向数组中添加元素的操作。具体步骤如下:1. 创建一个新的数组,长度比原数组大1。2. 使用System.arraycopy()方法将原数组的所有元素复制到新数组中。3. 将待添加的元素放置在新数组的最后
2023-10-07

怎么在java中遍历数组的全部元素

怎么在java中遍历数组的全部元素?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一
2023-06-14

js中怎么实现遍历dom元素

小编给大家分享一下js中怎么实现遍历dom元素,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!javascript是一种什么语言javascript是一种动态类型、
2023-06-14

python元组怎么添加元素

元组是不可变的数据类型,一旦创建后就无法修改元素。所以无法直接添加元素到元组中。但可以通过以下步骤间接添加元素到元组:创建一个新的元组,包含需要添加的元素。将原始元组和新的元素元组合并为一个新的元组。下面是一个示例代码:# 原始元组
python元组怎么添加元素
2024-02-29

java怎么往数组里添加元素

在Java中,如果想向数组中添加新的元素,需要创建一个新的数组,并将原数组中的元素复制到新数组中,同时将新元素添加到新数组的末尾。下面是一个示例代码:```java// 原始数组int[] originalArray = {1, 2, 3,
2023-08-19

java集合遍历删除指定元素怎么实现

在Java集合中遍历并删除指定的元素,可以使用迭代器来实现。以下是具体的步骤:1. 创建一个迭代器对象,使用集合的`iterator()`方法获取迭代器。2. 使用`hasNext()`方法判断是否还有下一个元素。3. 使用`next()`
2023-10-10

java中的集合元素怎么利用foreach进行遍历

本篇文章给大家分享的是有关java中的集合元素怎么利用foreach进行遍历,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。代码示例import java.util.*; pu
2023-05-31

怎么在java中使用LinkedHashMap添加元素

怎么在java中使用LinkedHashMap添加元素?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java的特点有哪些Java的特点有哪些1.Java语言作为
2023-06-14

python怎么向元组中添加元素

元组是不可变的数据结构,意味着你不能直接在元组中添加、删除或修改元素。但是你可以通过以下方法创建一个新的元组,包含原始元组的所有元素以及新添加的元素:```python# 创建一个空的元组my_tuple = ()# 创建一个含有元素的元组
2023-10-11

python字典怎么添加元素

本文小编为大家详细介绍“python字典怎么添加元素”,内容详细,步骤清晰,细节处理妥当,希望这篇“python字典怎么添加元素”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。python字典添加元素的方法:1、通
2023-07-04

JavaScript怎么添加删除元素

小编给大家分享一下JavaScript怎么添加删除元素,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!JS添加和删除元素的方法:1、使用“appendChild("
2023-06-14

JavaScript数组怎么添加元素

在JavaScript中,可以使用`push()`方法向数组中添加元素。例如,有一个空数组`arr`,想要向其中添加元素`1`,可以使用以下代码:```javascriptvar arr = [];arr.push(1);```现在,数组`
2023-10-12

php怎么遍历数组去掉空格元素

实现步骤:1、利用foreach语句循环遍历数组,语法“foreach ($array as $key => $value){循环语句块;}”;2、在循环体中,利用“==”运算符判断数组元素“$value”是否为空格,如果是则利用unset()函数根据键名“$key”删除该空格元素,语法“if($value==" "){unset($array[$key]);}”。本教程操作环境:windows7系
2022-06-29

python元组怎么添加变量元素

在Python中,元组是不可变的,即不能直接修改元组的元素。但是,可以通过以下方式添加变量元素到已有元组中:使用`+`运算符进行拼接:tup = (1, 2, 3)new_element = 4new_tup = tup + (new
python元组怎么添加变量元素
2023-10-28

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录