在上一篇博客,我们介绍了 Map 集合的一种典型实现 HashMap ,在 JDK1.8 中,HashMap 是由 数组+链表+红黑树构成,相对于早期版本的 JDK HashMap 实现,新增了红黑树作为底层数据结构,在数据量较大且哈希碰撞较多时,能够极大的增加检索的效率。了解 HashMap 的具体实现后,我们再来介绍由 HashMap 作为底层数据结构实现的一种数据结构——HashSet。(如果不了解 HashMap 的实现原理,建议先看看 HashMap,不然直接看 HashSet 是很难看懂的)

1、HashSet 定义

  HashSet 是一个由 HashMap 实现的集合。元素无序且不能重复。

 public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable

  

  和前面介绍的大多数集合一样,HashSet 也实现了 Cloneable 接口和 Serializable 接口,分别用来支持克隆以及支持序列化。还实现了 Set 接口,该接口定义了 Set 集合类型的一套规范。

2、字段属性

 //HashSet集合中的内容是通过 HashMap 数据结构来存储的
private transient HashMap<E,Object> map;
//向HashSet中添加数据,数据在上面的 map 结构是作为 key 存在的,而value统一都是 PRESENT
private static final Object PRESENT = new Object();

  第一个定义一个 HashMap,作为实现 HashSet 的数据结构;第二个 PRESENT 对象,因为前面讲过 HashMap 是作为键值对 key-value 进行存储的,而 HashSet 不是键值对,那么选择 HashMap 作为实现,其原理就是存储在 HashSet 中的数据 作为 Map 的 key,而 Map 的value 统一为 PRESENT(下面介绍具体实现时会了解)。

3、构造函数

  ①、无参构造

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

  直接 new 一个 HashMap 对象出来,采用无参的 HashMap 构造函数,具有默认初始容量(16)和加载因子(0.75)。

  ②、指定初始容量

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

  ③、指定初始容量和加载因子

     public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}

  ④、构造包含指定集合中的元素

     public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}

  集合容量很好理解,这里我介绍一下什么是加载因子。在 HashMap 中,能够存储元素的数量就是:总的容量*加载因子 ,新增一个元素时,如果HashMap集合中的元素大于前面公式计算的结果了,那么就必须要进行扩容操作,从时间和空间考虑,加载因子一般都选默认的0.75。

4、添加元素

     public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

  通过 map.put() 方法来添加元素,在上一篇博客介绍该方法时,说明了该方法如果新插入的key不存在,则返回null,如果新插入的key存在,则返回原key对应的value值(注意新插入的value会覆盖原value值)。

  也就是说 HashSet 的 add(E e) 方法,会将 e 作为 key,PRESENT 作为 value 插入到 map 集合中,如果 e 不存在,则插入成功返回 true;如果存在,则返回false。

5、删除元素

     public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}

  调用 HashMap 的remove(Object o) 方法,该方法会首先查找 map 集合中是否存在 o ,如果存在则删除,并返回该值,如果不存在则返回 null。

  也就是说 HashSet 的 remove(Object o) 方法,删除成功返回 true,删除的元素不存在会返回 false。

6、查找元素

     public boolean contains(Object o) {
return map.containsKey(o);
}

  调用 HashMap 的 containsKey(Object o) 方法,找到了返回 true,找不到返回 false。

7、遍历元素

 HashSet<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
//增强for循环
for(Integer i : set){
System.out.println(i);
}
//普通for循环
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}

JDK1.8源码(八)——java.util.HashSet 类的更多相关文章

  1. JDK1.8源码(八)——java.util.HashMap类

    https://www.cnblogs.com/javastack/p/12801870.html https://www.cnblogs.com/chanshuyi/p/java_collectio ...

  2. JDK1.8源码(五)——java.util.Vector类

    JDK1.8源码(五)--java.lang. https://www.cnblogs.com/IT-CPC/p/10897559.html

  3. JDK1.8源码(四)——java.util.Arrays 类

    java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用. 1.asList public static ...

  4. JDK1.8源码(四)——java.util.Arrays类

    一.概述 1.介绍 Arrays 类是 JDK1.2 提供的一个工具类,提供处理数组的各种方法,基本上都是静态方法,能直接通过类名Arrays调用. 二.类源码 1.asList()方法 将一个泛型数 ...

  5. JDK1.8源码(七)——java.util.HashMap 类

    本篇博客我们来介绍在 JDK1.8 中 HashMap 的源码实现,这也是最常用的一个集合.但是在介绍 HashMap 之前,我们先介绍什么是 Hash表. 1.哈希表 Hash表也称为散列表,也有直 ...

  6. JDK1.8源码(九)——java.util.LinkedHashMap 类

    前面我们介绍了 Map 集合的一种典型实现 HashMap ,关于 HashMap 的特性,我们再来复习一遍: ①.基于JDK1.8的HashMap是由数组+链表+红黑树组成,相对于早期版本的 JDK ...

  7. JDK1.8源码(五)——java.util.ArrayList 类

    关于 JDK 的集合类的整体介绍可以看这张图,本篇博客我们不系统的介绍整个集合的构造,重点是介绍 ArrayList 类是如何实现的. 1.ArrayList 定义 ArrayList 是一个用数组实 ...

  8. JDK1.8源码(六)——java.util.LinkedList 类

    上一篇博客我们介绍了List集合的一种典型实现 ArrayList,我们知道 ArrayList 是由数组构成的,本篇博客我们介绍 List 集合的另一种典型实现 LinkedList,这是一个有链表 ...

  9. JDK1.8源码(十一)——java.util.TreeMap类

    在前面几篇博客分别介绍了这样几种集合,基于数组实现的ArrayList 类,基于链表实现的LinkedList 类,基于散列表实现的HashMap 类,本篇博客我们来介绍另一种数据类型,基于树实现的T ...

随机推荐

  1. ES6躬行记(12)——数组

    ES6为数组添加了多个新方法,既对它的功能进行了强化,也消除了容易产生歧义的语法. 一.静态方法 1)of() ES6为Array对象新增的第一个静态方法是of(),用于创建数组,它能接收任意个参数, ...

  2. MySQL 索引及查询优化总结

    本文由云+社区发表 文章<MySQL查询分析>讲述了使用MySQL慢查询和explain命令来定位mysql性能瓶颈的方法,定位出性能瓶颈的sql语句后,则需要对低效的sql语句进行优化. ...

  3. Docker快速搭建LNMP环境

    一.使用Dockerfile制作镜像 前面的博客中已经介绍了如何基于容器制作镜像,此方法的原理是使用一个正在运行的容器,根据生产所需进行配置更改等操作后,使其满足生产环境,再将这个容器打包制作为镜像, ...

  4. ajax跨域请求,亲测有效

    跨域请求域有两种常用解决方案,jsonp和cors, 因为jsonp只能解决get请求问题,我这里用的是cors方法. js前端ajax请求: $.ajax({ url: "http://1 ...

  5. Asp.net Core 项目中如何使用 MongoDB 数据库

    内容来源 https://blog.csdn.net/qq_26900081/article/details/83272132 一.添加依赖 1.MongoDB.Driver 2.MongoDB.Bs ...

  6. php 日期时间类型带毫秒

    <?php date_default_timezone_set('PRC'); $mtimestamp = sprintf("%.3f", microtime(true)); ...

  7. Oracle day03 连表查询

    为什么要表连接进行查询? 查询部门名称为SALES的员工信息 如何进行表的连接查询? 两种方式:Sql 1992 和sql1999 sql1992sql分类    1.笛卡尔积 (表乘表)    2. ...

  8. 用JS编写一个函数,返回数组中重复出现过的元素

    用JS编写一个函数,返回数组中重复出现过的元素,见下面的代码: , , , , , , , ]; var getRepeat = function (arr) { var obj = {}; , le ...

  9. ffmpeg相关函数整理

    1.av_read_frame() 该函数用于读取具体的音/视频帧数据,从流中读取数据帧到 AVPacket,AVPacket保存仍然是未解码的数据 int av_read_frame(AVForma ...

  10. 【原】Java学习笔记011 - 数组

    package cn.temptation; import java.util.Scanner; public class Sample01 { public static void main(Str ...