Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 210|回复: 0

[默认分类] Java集合:HashSet的源码分析

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-15 14:04:20 | 显示全部楼层 |阅读模式
    Java集合---HashSet的源码分析 一、  HashSet概述:   HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元素。 二、  HashSet的实现:   对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成, HashSet的源代码如下:
    1. 1 public class HashSet<E>  
    2. 2    extends AbstractSet<E>  
    3. 3    implements Set<E>, Cloneable, java.io.Serializable  
    4. 4{  
    5. 5    static final long serialVersionUID = -5024744406713321676L;  
    6. 6  
    7. 7    // 底层使用HashMap来保存HashSet中所有元素。  
    8. 8    private transient HashMap<E,Object> map;  
    9. 9      
    10. 10    // 定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。  
    11. 11    private static final Object PRESENT = new Object();  
    12. 12  
    13. 13    /**
    14. 14     * 默认的无参构造器,构造一个空的HashSet。
    15. 15     *  
    16. 16     * 实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。
    17. 17     */  
    18. 18    public HashSet() {  
    19. 19    map = new HashMap<E,Object>();  
    20. 20    }  
    21. 21  
    22. 22    /**
    23. 23     * 构造一个包含指定collection中的元素的新set。
    24. 24     *
    25. 25     * 实际底层使用默认的加载因子0.75和足以包含指定
    26. 26     * collection中所有元素的初始容量来创建一个HashMap。
    27. 27     * @param c 其中的元素将存放在此set中的collection。
    28. 28     */  
    29. 29    public HashSet(Collection<? extends E> c) {  
    30. 30    map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));  
    31. 31    addAll(c);  
    32. 32    }  
    33. 33  
    34. 34    /**
    35. 35     * 以指定的initialCapacity和loadFactor构造一个空的HashSet。
    36. 36     *
    37. 37     * 实际底层以相应的参数构造一个空的HashMap。
    38. 38     * @param initialCapacity 初始容量。
    39. 39     * @param loadFactor 加载因子。
    40. 40     */  
    41. 41    public HashSet(int initialCapacity, float loadFactor) {  
    42. 42    map = new HashMap<E,Object>(initialCapacity, loadFactor);  
    43. 43    }  
    44. 44  
    45. 45    /**
    46. 46     * 以指定的initialCapacity构造一个空的HashSet。
    47. 47     *
    48. 48     * 实际底层以相应的参数及加载因子loadFactor为0.75构造一个空的HashMap。
    49. 49     * @param initialCapacity 初始容量。
    50. 50     */  
    51. 51    public HashSet(int initialCapacity) {  
    52. 52    map = new HashMap<E,Object>(initialCapacity);  
    53. 53    }  
    54. 54  
    55. 55    /**
    56. 56     * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。
    57. 57     * 此构造函数为包访问权限,不对外公开,实际只是是对LinkedHashSet的支持。
    58. 58     *
    59. 59     * 实际底层会以指定的参数构造一个空LinkedHashMap实例来实现。
    60. 60     * @param initialCapacity 初始容量。
    61. 61     * @param loadFactor 加载因子。
    62. 62     * @param dummy 标记。
    63. 63     */  
    64. 64    HashSet(int initialCapacity, float loadFactor, boolean dummy) {  
    65. 65    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);  
    66. 66    }  
    67. 67  
    68. 68    /**
    69. 69     * 返回对此set中元素进行迭代的迭代器。返回元素的顺序并不是特定的。
    70. 70     *  
    71. 71     * 底层实际调用底层HashMap的keySet来返回所有的key。
    72. 72     * 可见HashSet中的元素,只是存放在了底层HashMap的key上,
    73. 73     * value使用一个static final的Object对象标识。
    74. 74     * @return 对此set中元素进行迭代的Iterator。
    75. 75     */  
    76. 76    public Iterator<E> iterator() {  
    77. 77    return map.keySet().iterator();  
    78. 78    }  
    79. 79  
    80. 80    /**
    81. 81     * 返回此set中的元素的数量(set的容量)。
    82. 82     *
    83. 83     * 底层实际调用HashMap的size()方法返回Entry的数量,就得到该Set中元素的个数。
    84. 84     * @return 此set中的元素的数量(set的容量)。
    85. 85     */  
    86. 86    public int size() {  
    87. 87    return map.size();  
    88. 88    }  
    89. 89  
    90. 90    /**
    91. 91     * 如果此set不包含任何元素,则返回true。
    92. 92     *
    93. 93     * 底层实际调用HashMap的isEmpty()判断该HashSet是否为空。
    94. 94     * @return 如果此set不包含任何元素,则返回true。
    95. 95     */  
    96. 96    public boolean isEmpty() {  
    97. 97    return map.isEmpty();  
    98. 98    }  
    99. 99  
    100. 100    /**
    101. 101     * 如果此set包含指定元素,则返回true。
    102. 102     * 更确切地讲,当且仅当此set包含一个满足(o==null ? e==null : o.equals(e))
    103. 103     * 的e元素时,返回true。
    104. 104     *
    105. 105     * 底层实际调用HashMap的containsKey判断是否包含指定key。
    106. 106     * @param o 在此set中的存在已得到测试的元素。
    107. 107     * @return 如果此set包含指定元素,则返回true。
    108. 108     */  
    109. 109    public boolean contains(Object o) {  
    110. 110    return map.containsKey(o);  
    111. 111    }  
    112. 112  
    113. 113    /**
    114. 114     * 如果此set中尚未包含指定元素,则添加指定元素。
    115. 115     * 更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2))
    116. 116     * 的元素e2,则向此set 添加指定的元素e。
    117. 117     * 如果此set已包含该元素,则该调用不更改set并返回false。
    118. 118     *
    119. 119     * 底层实际将将该元素作为key放入HashMap。
    120. 120     * 由于HashMap的put()方法添加key-value对时,当新放入HashMap的Entry中key
    121. 121     * 与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true),
    122. 122     * 新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变,
    123. 123     * 因此如果向HashSet中添加一个已经存在的元素时,新添加的集合元素将不会被放入HashMap中,
    124. 124     * 原来的元素也不会有任何改变,这也就满足了Set中元素不重复的特性。
    125. 125     * @param e 将添加到此set中的元素。
    126. 126     * @return 如果此set尚未包含指定元素,则返回true。
    127. 127     */  
    128. 128    public boolean add(E e) {  
    129. 129    return map.put(e, PRESENT)==null;  
    130. 130    }  
    131. 131  
    132. 132    /**
    133. 133     * 如果指定元素存在于此set中,则将其移除。
    134. 134     * 更确切地讲,如果此set包含一个满足(o==null ? e==null : o.equals(e))的元素e,
    135. 135     * 则将其移除。如果此set已包含该元素,则返回true
    136. 136     * (或者:如果此set因调用而发生更改,则返回true)。(一旦调用返回,则此set不再包含该元素)。
    137. 137     *
    138. 138     * 底层实际调用HashMap的remove方法删除指定Entry。
    139. 139     * @param o 如果存在于此set中则需要将其移除的对象。
    140. 140     * @return 如果set包含指定元素,则返回true。
    141. 141     */  
    142. 142    public boolean remove(Object o) {  
    143. 143    return map.remove(o)==PRESENT;  
    144. 144    }  
    145. 145  
    146. 146    /**
    147. 147     * 从此set中移除所有元素。此调用返回后,该set将为空。
    148. 148     *
    149. 149     * 底层实际调用HashMap的clear方法清空Entry中所有元素。
    150. 150     */  
    151. 151    public void clear() {  
    152. 152    map.clear();  
    153. 153    }  
    154. 154  
    155. 155    /**
    156. 156     * 返回此HashSet实例的浅表副本:并没有复制这些元素本身。
    157. 157     *
    158. 158     * 底层实际调用HashMap的clone()方法,获取HashMap的浅表副本,并设置到  HashSet中。
    159. 159     */  
    160. 160    public Object clone() {  
    161. 161        try {  
    162. 162            HashSet<E> newSet = (HashSet<E>) super.clone();  
    163. 163            newSet.map = (HashMap<E, Object>) map.clone();  
    164. 164            return newSet;  
    165. 165        } catch (CloneNotSupportedException e) {  
    166. 166            throw new InternalError();  
    167. 167        }  
    168. 168    }  
    169. }
    复制代码
    三、 相关说明:   对于HashSet中保存的对象,请注意正确重写其equals和hashCode方法,以保证放入的对象的唯一性。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-26 09:23 , Processed in 0.361859 second(s), 37 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表