前言
Set是集合接口Collection的子类,该接口的常用的实现类简易结构图如下:
接下来我们就依次介绍下上图中的实现类:
1、HashSet类
先来看HashSet的源码,对其中部分内容进行分析介绍:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
{
private transient HashMap<E,Object> map;
/**
由源码可知,HashSet共有四个构造函数,底层的实现实为HashMap
*/
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);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
// 返回为HashMap中所有key的迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* 添加数据这个地方有一点特殊,HashSet只使用了HashMap中的键列(key),
* 对于value,则使用一个空的Object对象来填充。
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
}
hashSet的底层实现为HashMap,所以HashSet的大部分方法及用法与HashMap的都一样,关于HashMap的原理可以参考另一篇博客:Java集合框架——Map
2、LinkedHashSet类
LinkedHashSet类时HashSet的子类,下面是LinkedHashSet的部分源码:
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
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);
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
}
}
由LinkedHashSet源码可以知道,LinkedHashSet就是HashSet的一个子类,其构造方法都是沿用父类的构造方法,只是所有的构造方法都是使用的父类中一个默认的方法:
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
由此可以看出LinkedHashSet的底层实现就是LinkedHashMap,所以只要明白LinkedHashMap就可以了,关于LinkedHashMap的原理及相关内容可以参考博客:Java集合框架——Map
3、TreeSet类
先来上源码,以下是部分的源码内容,看看TreeSet类的实现:
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable
{
/**
* The backing map.
*/
private transient NavigableMap<E,Object> m;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* Constructs a set backed by the specified navigable map.
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
/**
* 先来看TreeSet的构造函数,TreeSet的底层实现是基于TreeMap来实现的
*/
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);
}
/**
* Adds all of the elements in the specified collection to this set.
*
* @param c collection containing elements to be added to this set
* @return {@code true} if this set changed as a result of the call
* @throws ClassCastException if the elements provided cannot be compared
* with the elements currently in the set
* @throws NullPointerException if the specified collection is null or
* if any element is null and this set uses natural ordering, or
* its comparator does not permit null elements
*/
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<?> cc = set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT);
return true;
}
}
return super.addAll(c);
}
}
TreeSet的底层实现为TreeMap,其中大部分方法都是走的TreeMap中的方法,所以可以参考博客中关于TreeMap部分的介绍内容;博文地址:Java集合框架——Map
TreeSet与上述两个实现类不同的是,TressSet可以通过比较器来控制Set中数据的顺序,可以使用默认的比较器,也可以自己实现比较器。
4、Set中实现类的使用介绍
接下来我们来介绍下上述介绍的几个实现类的简单使用:
public class Collection_Set {
private final static Comparator<String> comparator;
static {
comparator=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 倒序排列:o2.compareTo(o1)
// 正序排列:o1.compareTo(o2)
return o2.compareTo(o1);
}
};
}
public static void main(String[] args) {
Collection<String> coll=new ArrayList<String>();
coll.add("河北");
coll.add("河南");
coll.add("北京");
coll.add("广州");
//coll.add(null);
System.out.println("hashSet====================");
// 根据hashCode()计算值来确定值的位置
// 值可以为null
Set<String> hashSet=new HashSet<String>(coll);
for (String string : hashSet) {
System.out.println(string);
}
System.out.println("treeSet====================");
// 根据比较器中的策略来确定位置
// 值不能为null
Set<String> treeSet=new TreeSet<>(comparator);
treeSet.addAll(hashSet);
for (String string : treeSet) {
System.out.println(string);
}
System.out.println("linkedHashSet====================");
// 默认按照输入的顺序进行存储
// 值可以为null
Set<String> linkedHashSet=new LinkedHashSet<>(coll);
for (String string : linkedHashSet) {
System.out.println(string);
}
}
}
输出结果为:
hashSet====================
广州
河北
河南
北京
treeSet====================
河南
河北
广州
北京
linkedHashSet====================
河北
河南
北京
广州