Java Set 源码分析
一、Set
HashSet:按照Hash算法来存储集合中的元素,有良好的存取和查找性能。 特点:1、无序;2、线程不同步3、集合元素值可以为null 使用equals()+hashCode()两个返回值都相等来判断两个元素是否相等。 如果hash冲突,HashSet会在同一位置使用链式结构来保存多个对象。
TreeSet:实现了SortSet()接口,采用的数据结构是红黑树。 最大的特点是有序(提供Comparable()接口支持自然排序和自定义排序) 当把一个对象加入TreeSet时,会调用compareTo()方法与容器中的元素比较,然后根据红黑树结构找到它的存储位置。
LinkedHashSet:与HashSet类似,使用元素的HashCode()值来存储元素。 不同点是同时使用了链表来维护元素的次序,当遍历元素时,LinkedHashSet将按照元素的添加顺序来访问集合。
二、HashSet
(1)HashSet继承自AbstractSet,实现了Set、Cloneable和Serializable接口。
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
(2)内部实现:内部是用HashMap实现的。
public HashSet() {
map =
new HashMap<>();
}
(3)构造函数:默认构造函数是new 一个HashMap。如果是传入Collections的构造函数,其大小为Collections的大小的1.3333倍。当然也可以直接传入int类型的初始容量大小。
public HashSet(Collection<? extends E> c) {
map =
new HashMap<>(Math.max((
int) (c.size()/
.75f) +
1,
16));
addAll(c);
}
(4)add方法:调用的是map的put方法。
public boolean add(E e) {
return map.put(e, PRESENT)==
null;
}
三、TreeSet
(1)TreeSet实现了NavigableSet, Cloneable,和Serializable接口。其中,NavigableSet是扩展的 SortedSet,具有了为给定搜索目标报告最接近匹配项的导航方法。
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
(2)默认构造方法:底层实现是TreeMap
public TreeSet() { this(new TreeMap
(3)add方法:直接调用的是TreeMap的put方法。TreeMap底层是用红黑树实现的,就是这个Entry,然后通过一个compare函数不断比较,小于就放左子树,大于就放右子树,如果重复就不入树,从而保证了数据的唯一。插入完毕后会调用一个fixAfterInsertion()方法,来调整红黑树,保持平衡。
public boolean
add(E e) {
return m.put(e, PRESENT)==
null;
}
public V
put(K key, V
value) {
Entry<K,V> t = root;
if (t ==
null) {
compare(key, key);
root =
new Entry<>(key,
value,
null);
size =
1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
Comparator<? super K> cpr = comparator;
if (cpr !=
null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp <
0)
t = t.left;
else if (cmp >
0)
t = t.right;
else
return t.setValue(
value);
}
while (t !=
null);
}
else {
if (key ==
null)
throw new NullPointerException();
@SuppressWarnings(
"unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp <
0)
t = t.left;
else if (cmp >
0)
t = t.right;
else
return t.setValue(
value);
}
while (t !=
null);
}
Entry<K,V> e =
new Entry<>(key,
value, parent);
if (cmp <
0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
四、LinkedHashSet
(1)继承自HashSet,实现了Set, Cloneable,和Serializable接口。
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
(2)默认构造函数:默认的容量是16,负载因子是0.75.
public LinkedHashSet(
int initialCapacity,
float loadFactor) {
super(initialCapacity, loadFactor,
true);
}
(3)LinkedHashSet的具体实现,通过super来看,是HashSet中的带参数的构造方法,具体实现的其实是LinkedHashMap
HashSet(
int initialCapacity,
float loadFactor,
boolean dummy) {
map =
new LinkedHashMap<>(initialCapacity, loadFactor);
}