PRELOADER

当前文章 : 《HashSet源码解读》

10/8/2019 —— 

构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
//一个空的构造函数,new一个hashMap对象实例出来。默认初始容量是16,加载因子是0.75,这些都市HashMap的知识

public HashSet() {
map = new HashMap<>();
}
//讲一个新的collection转换为一个HashSet集合。这个构造和空构造函数都市规定需要写的。
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//自己初始化容量和加载因子的大小
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
//初始化容量大小,加载因子用默认的
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//这个就是那个default权限的构造方法,只能在包内可见,这个作用是给HashSet的子类 LinkedHashSet用的,LinkedHashSet中并没有什么别的方法,就四个构造方法,并且构造方法也是调用HashSet中的构造方法,也就是调用这个构造方法,来使其底层的实现原理为LinkedHashMap,而不是HashMap。所以该方法的作用就在此处。
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

add方法

1
2
3
4
5
6
7
8
9
10
11
//这个方法就可以得知HashSet添加的元素是不能够重复的,原因是什么呢,set将每次添加的元素度是通过map中的key来保存,当有相同的key时,也就是添加了相同的元素,那么map会讲value给覆盖掉,而key还是原来的key,所以,这就是set不能够重复的原因。这个方法的PRESENT可以看下面的注释,
//返回值的式子的意思很好理解,map中增加元素是先通过key查找有没有相同的key值,如果有,则覆盖value,返回oldValue。没有,则创建一个新的entry,并且返回null值。如果key等于null,也会返回null值。
  所以return会有一个==null的判断

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

//PERSENT:通过注释,可以知道这个一个假的值,为了符合map的key,value的方式才用到这个值。
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

remove方法

1
2
3
4
5
6
7
8
9
10
//map中通过key来移除对应的元素,如果有该key,会返回其value值,没有,则返回null
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}

//HashMap中的remove,看一眼就懂了。
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}

contains方法

1
2
3
4
5
6
7
8
9
//是否包含某值,也就是判断HashMap中是否有这个Key值。
public boolean contains(Object o) {
return map.containsKey(o);
}
//HashMap中的containsKey方法
public boolean containsKey(Object key) {
//也就是通过key能不能找得到其entry,找得到就说明有。找不到就没有
return getEntry(key) != null;
}

isEmpty方法

1
2
3
4
//非常简单,都市通过调用map的方法 
public boolean isEmpty() {
return map.isEmpty();
}

size方法

1
2
3
4
//看set中有多少个元素,也就是看map中有多少个元素
public int size() {
return map.size();
}

iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//可以重点看一下这个迭代器,这个迭代器在HashMap中就已经构建好了。
public Iterator<E> iterator() {
return map.keySet().iterator();
}
//keySet这个方法也就是为了new一个KeySet这个类出来,来看看KeySet这个类
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
//KeySet类是HashMap中的一个内部类,继承了AbstractSet,所以他也是一个set,其中就是一个写普通的操作,看一下这个newKeyIterator是什么
private final class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
HashMap.this.clear();
}
}
//newKeyIterator
Iterator<K> newKeyIterator() {
return new KeyIterator();
}
//KeyIterator,重点来了,KeyIterator。看名字就知道,就对key进行迭代的迭代器,也就是为set量身打造的,因为set存放的元素就是存放在HashMap中的key,所以为了能够迭代set,HashMap
就实现了这个专门遍历key的迭代器,通过继承HashIterator,能够每次拿到nextEntry。也就能拿到对应的可以了,可以看下面的图,看下HashIterator有哪些方法就明白了
private final class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}

clone方法

1
2
3
4
5
6
7
8
9
10
//复制一个HashSet,但是只是复制原HashSet的浅表副本,
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}