一、原理
1、HashSet
hashset底层其实维护的是一个HashMap实例。底层数据结构是哈希表。综合了数组和链表的优点。其有以下等特点:
(1) 不允许存放重复值的集合(通过hashCode()函数及equals()函数来判断是否重复)。
(2)不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化 (内部维护的是hashmap,采用hash取模确定数组索引位置,然后在存入链表)。
(3) HashSet是非线程安全的。
(4) 集合元素值可以是nul。
/**
* 维护的hashMap实例
*/
private transient HashMap<E,Object> map;
/**
* 无参构造器,创建一个hashMap实例,默认的加载因子是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);
}
/**
* 指定初始容量,加载因子为默认的0.75
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
/**
* 指定容量,指定加载因子,区分其他不同访问权限的构造函数
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
note:如果需要把某个类的对象保存到HashSet集合中,重写这个类的equals方法和hashCode方法时,应尽量保证两个对象通过equals比较返回true时,他们的hashCode方法返回值也相等。如果equals比较不同的时候,尽量让hashcode的值不同,以提升插入的效率。
2、TreeSet
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。底层数据结构采用的是红黑树。默认排序从小到大。内部维护了一个NavigableMap<E,Object>,该map继承SortMap。
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
/**
* 该map继承SortMap
*/
private transient NavigableMap<E,Object> m;
//
private static final Object PRESENT = new Object();
/**
*
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
/**
*
*/
public TreeSet() {
this(new TreeMap<E,Object>());
}
/**
*
*/
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
/**
*
*/
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
/**
*
*/
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
}

相较HashSet,TreeSet中多有以下函数:
(1)Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回nul。
(2)Object first():返回集合中的第一个元素。
(3)Object last():返回集合中的最后一个元素。
(4)Object lower(Object e):返回指定元素之前的元素。
(5)Object higher(Object e):返回指定元素之后的元素。
(6)SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾。
(7)SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成。
(8)SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成。
3、LinkedHashSet
linkedHashSet是hashSet的一个子类,是基于LinkedHashMap实现的。
/**
* 继承HashSet
*/
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2851667679971038690L;
/**
* 指定容量及加载因子的构造函数
*/
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
/**
* 指定容量的构造函数,其加载因子用默认的0.75
*/
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
/**
* 无参构造函数,默认容量16,加载因子为0.75
*/
public LinkedHashSet() {
super(16, .75f, true);
}
/**
* 包含指定集合的构造函数
*/
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
/**
* java8的可分割迭代器
*/
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
}
}
上面便是LinkedHashSet的全部代码,这里面我们并没有发现LinkedHashMap的踪影,为何说LinkedHashSet是基于LinkedHashMap实现的呢?
下面我们可以看下其构造函数中调用父类的构造函数。
/**
* 指定容量及加载因子的构造函数,其中dummy参数是用来区分其他的构造函数,实现重载。
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
二、线程安全的使用
使用Colletcions这个工具类syn方法类创建个线程安全的set.Set<String> synSet = Collections.synchronizedSet(new HashSet<>())。

本文详细解析了Java集合框架中的HashSet、TreeSet和LinkedHashSet的原理,包括它们的数据结构和特性。HashSet基于HashMap实现,不保证元素顺序且非线程安全;TreeSet采用红黑树,提供排序和多种操作;LinkedHashSet基于LinkedHashMap,保持插入顺序。同时,介绍了如何使用Collections工具类创建线程安全的Set。

1951

被折叠的 条评论
为什么被折叠?



