JAVA集合Set之HashSet详解

HashSet这个类实现了Set集合,实际为一个HashMap的实例。并且HashSet提供了三个构造函数

大家好,又见面了,我是你们的朋友全栈君。

HashSet这个类实现了Set集合,实际为一个HashMap的实例。对集合的迭代次序没有任何保证; 特别是,它不能保证订单会随着时间的推移保持不变。这个类允许null 元素。

JAVA集合Set之HashSet详解

并且HashSet提供了三个构造函数:

JAVA集合Set之HashSet详解

无参数的构造函数,此构造函数创建一个大小为16的容器,加载因子为0.75(容器的大小始终是2的冥,默认为16不在赘述,在后面文章中介绍另外的构造函数,添加指定值的时候会介绍程序是如何保证始终是2的冥,透露一点如果我们传值为5的一个容器大写,那么创建的容器实际大小为8,感兴趣的可以先去看一下算法。),具体看一下实例化一个hashSet的具体参数,并且为了保证速度,我们在实例化的这个参数的时候尽量不要把容器设置的太大,或者加载因子设置太小,后面在说得到HashSet的另外三个构造函数。

Set<String> set =new HashSet<>();

JAVA集合Set之HashSet详解

由此图我们可以看到确实实例化了一个容量为16的HashMap,其中loadFactor为加载因子,当容量*加载因子=threshold,

为这个容器的临界值,当存储的元素到了这个临界值,那么容器就会自动扩容。

那么我接下来思考,容器是怎么保证添加的元素不重复的呢?(由于Set取值的时候是调用值本身来取值的,所以不能重复,如果重复了,根据值去取的时候就会不知道取哪一个。list是根据下标map是根据具体key取值

接下来我们看一下HashSet的add方法:

JAVA集合Set之HashSet详解

这个方法实际上是添加的一个put方法,描述的意思是:向这个set集合中添加元素,如果这个元素没有在集合中则添加到这个集合中。如果这个集合已经存在元素调用将离开。(其中PRESENT)

JAVA集合Set之HashSet详解

K为我们添加的参数,V为一个Object的定值。

下面我们看一下具体的put方法:

JAVA集合Set之HashSet详解

如果key为空,我们添加一个null=value的一个元素到容器里面,如果此时容器中有一个k,v 为 null=“1234”的元素,我们在添加一个null= “456”的一个元素,容器是怎么计算的:

我们看一下这个方法return putForNullKey(value):

JAVA集合Set之HashSet详解

卸载这个put空的key。什么意思?就是删除并替换的意思。

会循环拿出容器里面的元素,e=table[0],然后判断e != null 说明这个集合中是有元素的,那么紧接着开始判断,因为是K,V的形式,拿到这个k判断是否为空,如果为空,那么就用当前的value值替换原来对应的value值,也就是 null = 1234 的这个元素被null = 456 的元素替换掉。

如果第一个e=table[0]的元素,e=null 那么就不在进入这个方法,直接modCount 做累加,然后添加这个key=null,value=456的值。上面是添加key=null,后面讲addEntry方法的具体实现。

下面我们分析具体添加的实现,来理解key是如何保证key不重复的:

其中

JAVA集合Set之HashSet详解

为计算的具体hash值,具体实现如下:

JAVA集合Set之HashSet详解

useAltHashing具体是什么目前还没有理解,我们就按默认的false来计算这个hash值。

^为异或运算符这里简单说一下这个异或:

^是异或运算符(把数据转换成二进制,然后按位进行运算)。
运算规则:0^0 = 0, 1^0 = 1,  0^1 = 1,  1^1 = 0,运算对象相同为0,不同为1.
如:3^5 的运算过程为:
    (1)先将3和5转换成二进制的11和101
    (2)再按对应的位分别进行运算,11位数不足补零
             011
       ^   101
      ———–
             110
     (3)运算结果转换成10进制:6
 
异或运算的三个个特点:
    (1) 0^0=0,   0^1=1   0与任何数异或=任何数
    (2) 1^0=1,   1^1=0   1与任何数异或 =任何数取反
    (3) 任何数异或自己=把自己置0

还有 | & 可以百度了解下

然后简单介绍一下HashCode的算法:下面说两种

1.Integer的算法:

JAVA集合Set之HashSet详解

return当前的一个值,这个比较简单。

2.String的算法:

JAVA集合Set之HashSet详解

String中的hash算法,我们以int h = hash; h = 0 为基础算:例如传值为:String str = “srt”;

char val[] = {‘s’,’r’,’t’}

循环获取数组val的值,其中  h = 31 * h + val[i],val[i] 获取的是ASCII十进制的对应值,循环计算相加。最后返回具体的hash值。

最后在

JAVA集合Set之HashSet详解

这样计算出具体的hash值,也就是存储在map中的具体位置,相当于数组中的下标,所以效率上是非常快的。

后面就好理解了:

根据hash得到具体的位置,然后判断这个位置上面你的值是否hash一样并且key是否一样,如果一样,那么就替换掉,如果不一样就填加进去,具体添加方法为:

JAVA集合Set之HashSet详解

其中处理为:

JAVA集合Set之HashSet详解

添加值到容器中,在适当的时候扩容,什么时候扩容,当当前size >= threshold,临界值时候,扩容当前table大小的两倍,如16,到了size= 12 时候扩容到32.

具体添加如下:

JAVA集合Set之HashSet详解

另外三个构造函数简答列举一下:

HashSet(Collection<? extends E> c)
构造一个包含指定集合中的元素的新集合。  
HashSet(int initialCapacity)
构造一个新的空集合; 背景HashMap实例具有指定的初始容量和默认负载因子(0.75)。  
HashSet(int initialCapacity, float loadFactor)
构造一个新的空集合; 背景HashMap实例具有指定的初始容量和指定的负载因子。 

这些都有在jdk的API中可以具体看一下。

最后总结一下:

此文章主要介绍了一下Set的一种实现HashSet的具体实现和保证key不重复的源码算法和原因。并且在最后说明一下上面忘记了:此实现不同步,为线程不安全的实现,如果有多个线程同时访问这个容器(HashSet),并对立面的元素进行了修改,则需要在外部同步。保证数据的冥等性(幂等是数据中得一个概念,表示N次变换和1次变换的结果相同。

后面后再其他文章分别介绍TreeSet和LinkedHashSet

如果有对此文好的建议欢迎评价交流。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/124684.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月3日 下午11:35
下一篇 2022年4月4日 上午6:00


相关推荐

  • sqljdbc4.jar和sqljdbc.jar下载「建议收藏」

    sqljdbc4.jar和sqljdbc.jar下载「建议收藏」官网下载:windows版本http://go.microsoft.com/fwlink/?LinkId=144633&amp;clcid=0x804UNIX版本http://go.microsoft.com/fwlink/?LinkId=144635&amp;clcid=0x804  推荐几个网站:http://maven.ibiblio.org/maven/http…

    2022年7月16日
    21
  • protostuff报错[通俗易懂]

    protostuff报错[通俗易懂]themethodmergeFrom(byte[],T,Schema)inthetype isnotapplicableforthe。。。。。如果出现以上报错,说参数类型不匹配,RuntimeSchema和Schema类型无法转换,有很大的概率是倒包倒错了。要注意,需要导入的是:io.protostuffprotostuff-core1.5.2

    2022年5月2日
    75
  • U盘安装window系统[通俗易懂]

    U盘安装window系统[通俗易懂]U盘安装window系统:1.制作系统启动U盘,推荐使用老毛桃。2.电脑上插入U盘,启动系统,选择U盘启动。3.进入老毛桃选择界面,选择生成PE系统。推荐win8,之前在一个戴尔电脑上使用win

    2022年8月1日
    9
  • 学会阅读Java字节码

    学会阅读Java字节码1 Class 文件基础 1 文件格式 Class 文件的结构不像 XML 等描述语言那样松散自由 由于它没有任何分隔符号 所以 以上数据项无论是顺序还是数量都是被严格限定的 哪个字节代表什么含义 长度是多少 先后顺序如何 都不允许改变 2 数据类型仔细观察上面的 Class 文件格式 可以看出 Class 文件格式采用一种类似于 C 语言结

    2025年10月28日
    7
  • ipv6双向网关_IPv4_IPv6转换网关·····[通俗易懂]

    IPV4/IPV6转换网关的研究与设计摘要:随着计算机网络应用的飞速进步,现有的IP通信协议(IPv4协议)已展现出众多的问题,如不能适应新的网络应用、地址资源即将耗尽以及对安全性无法保证等。IPv6是继IPv4后出现的新一代通信协议,它的出现为互联网的发展带来了新契机。IPv6的众多优势成为取代IPv4必然的发展。本文从IPv6协议本身出发,阐述了IPv6协议及其与IPv4协议的比较,对目前现有…

    2022年4月9日
    62
  • mysql 1032 1062_MySQL 1032和1062跳过错误总结

    mysql 1032 1062_MySQL 1032和1062跳过错误总结MySQL 跳过错误传统复制情况 slave exec mode global 级别 IDEMPOTENTor IDEMPOTENTmo key

    2026年3月26日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号