一,Set
从Java源码看,java是先实现了Map,然后通过包装一个所有value都为null的Map实现了Set集合
Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入
1.HashSet
- 不能保证元素的排列顺序,顺序可能与添加顺序不同
- HashSet不是同步的,如果多个线程同时访问一个HashSet,假设有两个或者两个以上线程同时修改了HashSet集合,则必须通过代码来保证其同步
- 集合元素值可以是null
- HashSet结合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等
2.LinkedHashSet
与HashSet类似,使用元素的hashCode值来存储元素,不同点是同时使用了链表来维护元素的次序,当遍历元素时,会按照元素的添加顺序来访问集合
3.TreeSet
实现了SortedSet接口,采用的数据结构是红黑树,最大的特点是有序(提供Comparable接口支持自然排序和自定义排序),当把一个对象加入TreeSet时,会调用compareTo方法与容器中的元素进行比较,然后根据红黑树结构找到它的存储位置
二,HashSet
1.继承结构
HashSet继承AbstractSet抽象类,实现了Set、Cloneable、Serializable接口
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
2.构造函数
都是创建一个map实例对象,HashSet对象的默认大小与HashMap一样都是16,且大小只能是2的幂次方
private transient HashMap<E,Object> map;
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
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);
}
3.add方法
调用的是map的put方法,有返回值,返回值由map的put方法决定,map调用put(key,value),如果存在key,map即返回此key对应的value,则这里add返回false
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
4.iterator方法
HashSet并没有提供类似于get的方法,只提供获取访问元素的迭代器对象,获取map的key集合的迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
5.size等其他各种方法,也是通过委托给map来实现
public int size() {
return map.size();
}
三,LinkedHashSet
1.继承结构
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);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
都是super调用父类HashSet的构造函数来实现的:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
由此可以看出,LinkedHashSet借助于LinkedHashMap来实现
四,TreeSet
1.继承结构
NavigableSet是扩展的SortedSet,具有为了给定搜索目标报告最接近匹配项的导航方法
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
2.构造方法
底层实现时TreeMap
public TreeSet() {
this(new TreeMap<E,Object>());
}
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); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
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;
}
参考:
https://blog.csdn.net/u014282557/article/details/77756546
https://blog.csdn.net/u010412719/article/details/80301711