JavaSE_坚持读源码_HashSet对象_Java1.7

Posted rocker-pg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE_坚持读源码_HashSet对象_Java1.7相关的知识,希望对你有一定的参考价值。

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码:

 1 package java.util;
 2 
 3 public class HashSet<E>
 4     extends AbstractSet<E>
 5     implements Set<E>, Cloneable, java.io.Serializable
 6 {
 7     static final long serialVersionUID = -5024744406713321676L;
 8     
 9     //    使用 HashMap 的 key 保存 HashSet 中的所有元素
10     private transient HashMap<E,Object> map;
11     
12     //    定义一个虚拟的 Object 对象作为 HashMap 的 value
13     private static final Object PRESENT = new Object();
14 
15     //    初始化一个 HashSet ,底层会初始化一个 HashMap
16     public HashSet() {
17         map = new HashMap<>();
18     }
19 
20     public HashSet(Collection<? extends E> c) {
21         map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
22         addAll(c);
23     }
24     
25     //    以指定的 initialCapacity 和 loadFactor 创建一个 HashSet
26     //    其实就是以相应的参数创建 HashMap
27     public HashSet(int initialCapacity, float loadFactor) {
28         map = new HashMap<>(initialCapacity, loadFactor);
29     }
30 
31     public HashSet(int initialCapacity) {
32         map = new HashMap<>(initialCapacity);
33     }
34 
35     HashSet(int initialCapacity, float loadFactor, boolean dummy) {
36         map = new LinkedHashMap<>(initialCapacity, loadFactor);
37     }
38     
39     //    调用 map 的 keySet 来返回所有的 key
40     public Iterator<E> iterator() {
41         return map.keySet().iterator();
42     }
43     
44     //    调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 HashSet 里的元素的个数
45     public int size() {
46         return map.size();
47     }
48     
49     //    调用 HashMap 的 isEmpty() 方法判断该 map 是否为空
50     //    当 map 为空时,对应的 HashSet 也为空
51     public boolean isEmpty() {
52         return map.isEmpty();
53     }
54 
55     //    调用 HashMap 的 containsKey() 判断是否包含指定的 key
56     //    HashSet 的所有元素就是通过 HaseMap 的 key 保存的
57     public boolean contains(Object o) {
58         return map.containsKey(o);
59     }
60 
61     //    将指定元素放入 HashSet 中,也是将该元素作为 key 存入到 HashMap 中
62     public boolean add(E e) {
63         return map.put(e, PRESENT)==null;
64     }
65     
66     //    调用 HashMap 的 remove(o) 删除指定的 Entry ,也就是删除了 HashSet 对应的元素
67     public boolean remove(Object o) {
68         return map.remove(o)==PRESENT;
69     }
70 
71     //    调用 HashMap 的 clear() 清空所有的 Entry ,也就清空 HashSet 中的所有元素
72     public void clear() {
73         map.clear();
74     }
75 
76     ...
77 
78 }

 

由上面源程序可以看出,HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。

 

HashMap 的 put 与 HashSet 的 add

由于 HashSet 的 add() 方法添加集合元素时实际上转变为调用 HashMap 的 put() 方法来添加 key-value 对,当新放入 HashMap 的 Entry 中 key 与集合中原有 Entry 的 key 相同(hashCode() 返回值相等,通过 equals 比较也返回 true),新添加的 Entry 的 value 将覆盖原来 Entry 的 value,但 key 不会有任何改变,因此如果向 HashSet 中添加一个已经存在的元素,新添加的集合元素(底层由 HashMap 的 key 保存)不会覆盖已有的集合元素。

以上是关于JavaSE_坚持读源码_HashSet对象_Java1.7的主要内容,如果未能解决你的问题,请参考以下文章

JavaSE_坚持读源码_Class对象_Java1.7

21_JavaSE_HashSet类和HashMap类

Java源码初学_HashSet&LinkedHashSet

JavaSE_集合(Set)

java基础进阶篇_HashSet------java源码栈

读Vue源码二 (响应式对象)