HashSet 无序集合类

  • 实现了Set接口
  • 内部通过HashMap实现
// HashSet
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L; //重要:HashMap HashSet就是通过HashMap保存数据, HashSet的值就是HashMap的key
private transient HashMap<E,Object> map; // 使用transient修饰不会被序列化 //HashMap 为<key, value>的键值对, 既然HashSet的值就是HashMap的key, 那么HashMap的值呢,当然就是这个PRESENT,HashMap所有的value都是同一个对象
private static final Object PRESENT = new Object(); // 默认构造函数,创建一个HashMap对象
public HashSet() {
map = new HashMap<>();
} //将一个已知的collection转换为HashSet
public HashSet(Collection<? extends E> c) {
//Collection<? extends E> c 限制了类型上限为E,也就是c只能是E类型或E的子类,防止参数是非Set类型
//如果没有指定HashMap的capacity, 那么默认的就是16
//根据 threshold = capacity * loadFactor, 可以计算出 capacity
//Math.max((int) (c.size()/.75f) + 1, 16) 这个意思就是capacity如果没超过16, 那么就直接使用默认的16
// 容量设置为4/3倍
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
//将已知的collection转换为HashSet的方法
//addAll方法是HashSet的父类AbstractCollection的方法,为了便于阅读,会将代码粘贴在下面
addAll(c);
}
// 带有初始容量和因子的构造函数
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
} public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
} HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
} //addAll方法是HashSet的父类AbstractCollection的方法
public boolean addAll(Collection<? extends E> c) {
boolean modified = false; // 只要添加了元素就返回true
for (E e : c)
//此处的add方法由HashSet重写实现
if (add(e))
modified = true;
return modified;
} //HashSet的核心方法来了, 没错,就这么简单
public boolean add(E e) {
//应证了上面所说的key为HashSet的值
return map.put(e, PRESENT)==null;
} //剩下这些方法都是跟Map相关的了,只要熟悉了HashMap, 那就太简单了,就不说了
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
} public void clear() {
map.clear();
} }

补充

泛型

泛型的上限通配符<? extends T>

<? extends T>是 Upper Bound(上限) 的通配符,用来限制元素的类型的上限,比如  

List<? extends Fruit> fruits;
表示集合中的元素类型上限为Fruit类型,即只能是Fruit或者Fruit的子类。

泛型的下限通配符<? super T>

<? super E> 是 Lower Bound(下限) 的通配符 ,用来限制元素的类型下限,比如

List<? super Apple> apples;
表示集合中元素类型下限为Apple类型,即只能是Apple或Apple的父类。

参考

java集合-HashSet源码解析的更多相关文章

  1. Java集合-ArrayList源码解析-JDK1.8

    ◆ ArrayList简介 ◆ ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAcc ...

  2. Java集合---LinkedList源码解析

    一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...

  3. java集合类型源码解析之ArrayList

    前言 作为一个老码农,不仅要谈架构.谈并发,也不能忘记最基础的语言和数据结构,因此特开辟这个系列的文章,争取每个月写1~2篇关于java基础知识的文章,以温故而知新. 如无特别之处,这个系列文章所使用 ...

  4. java集合-HashMap源码解析

    HashMap 键值对集合 实现原理: HashMap 是基于数组 + 链表实现的. 通过hash值计算 数组索引,将键值对存到该数组中. 如果多个元素hash值相同,通过链表关联,再头部插入新添加的 ...

  5. java集合类型源码解析之PriorityQueue

    本来第二篇想解析一下LinkedList,不过扫了一下源码后,觉得LinkedList的实现比较简单,没有什么意思,于是移步PriorityQueue. PriorityQueue通过数组实现了一个堆 ...

  6. Java泛型底层源码解析-ArrayList,LinkedList,HashSet和HashMap

    声明:以下源代码使用的都是基于JDK1.8_112版本 1. ArrayList源码解析 <1. 集合中存放的依然是对象的引用而不是对象本身,且无法放置原生数据类型,我们需要使用原生数据类型的包 ...

  7. 【java集合框架源码剖析系列】java源码剖析之HashSet

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...

  8. Java集合框架源码(二)——hashSet

    注:本人的源码基于JDK1.8.0,JDK的版本可以在命令行模式下通过java -version命令查看. 在前面的博文(Java集合框架源码(一)——hashMap)中我们详细讲了HashMap的原 ...

  9. 【java集合框架源码剖析系列】java源码剖析之TreeSet

    本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...

随机推荐

  1. qml demo分析(maskedmousearea-异形窗口)

    一.效果展示 如本文的标题所示,这篇文章分析的demo是一个异形窗口,主要展示鼠标在和异形区域交互的使用,效果如图1所示,当鼠标移动到白云或者月亮上时,相应的物体会高亮,当鼠标按下时,物体会有一个放大 ...

  2. .NET Core微服务之基于Ocelot+Butterfly实现分布式追踪

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.什么是Tracing? 微服务的特点决定了功能模块的部署是分布式的,以往在单应用环境下,所有的业务都在同一个服务器上,如果服务器出现错 ...

  3. 并发系列(2)之 ThreadLocal 详解

    本文将主要结合源码讲述 ThreadLocal 的使用场景和内部结构,以及 ThreadLocalMap 的内部结构:另外在阅读文本之前只好先了解一下引用和 HashMap 的相关知识,可以参考 Re ...

  4. base64字符串转文件,以及ngImgCrop裁剪图片并上传保存到服务器示例

    base64字符串是包含文件格式的文件字符串,例如:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAgAElE ...

  5. ## 本篇文章对linux常用的一些命令做一下总结,如有需要补充以及不懂得地方,请在下方留言 适合于linux初学者,以及对命令掌握不牢的用来备忘

    本篇文章对linux常用的一些命令做一下总结,如有需要补充以及不懂得地方,请在下方留言 适合于linux初学者,以及对命令掌握不牢的用来备忘一,磁盘管理1.显示当前目录位置 pwd2.切换目录 cd ...

  6. web开发布局---传统布局篇

    1.传统布局 盒状模型结合 display 属性.float 浮动以及 position 定位属性设计的各式传统布局形式. 2.说再多不如动手实践,下面举三个例子 html 部分代码: <sec ...

  7. python的学习笔记01_3 基本运算符 流程控制if while 字符串常用办法

    基本运算符 运算符 计算机可以进行的运算有很多种,可不只加减乘除这么简单,运算按种类可分为算数运算.比较运算.逻辑运算.赋值运算.成员运算.身份运算.位运算,今天我们暂只学习算数运算.比较运算.逻辑运 ...

  8. Spinner之下拉多选,监听ID后显示不同Frgment页面

    本人安卓小白,公司最近项目需要用到不同的类型的用户注册,周末下午写完记录一下. 网上找了一堆没有适合自己的(或者说我没找到),写的比较基础,欢迎大家多多指导. 老规矩,先上效果图 网上在线合成的GIF ...

  9. Python安装第三方包(模块/工具)出现链接超时,网速慢,安装不上的问题如何解决

    之前我的电脑重新装了系统以后,发现安装完Python后, 使用pip linstall 安装第三方包的时候,网速慢的一匹 有时候只有几百b/s ,而且还动不动就会出现无法安装,链接超时等问题. 今天我 ...

  10. Java:配置环境(Mac)——MySQL

    1.官网下载 2.双击开始安装,一直下一步 用旧版的密码加密 自己写个密码,最少8位 3.测试 打开系统偏好设置 4.mysql需要在系统环境变量里 1)在终端输入mysql,没有指令说明.此时就还不 ...