Java集合-Set
# Java集合-Set
set
继承了collection
的接口,而set
集合是不允许有重复元素的
SortedSet
继承了 Set
的接口。SortedSet
中的内容是排序的唯一值,排序的方法是通过比较器(Comparator)。
NavigableSet
继承了 SortedSet
的接口。它提供了丰富的查找方法:如"获取大于/等于某值的元素"、“获取小于/等于某值的元素”等等。
HashSet
类依赖于 HashMap
,它实际上是通过 HashMap
实现的。HashSet
中的元素是无序的、散列的。
TreeSet
类依赖于 TreeMap
,它实际上是通过 TreeMap
实现的。TreeSet
中的元素是有序的,它是按自然排序或者用户指定比较器排序的 Set。
LinkedHashSet
是按插入顺序排序的 Set。
EnumSet
是只能存放 Emum 枚举类型的 Set。
# HashSet类
HashSet
是通过HashMap
来实现的,因此HashSet
中的元素是无序的、散列的。具有以下特点:
HashSet
通过继承AbstractSet
实现了Set
接口中的骨干方法。HashSet
实现了Cloneable
,所以支持克隆。HashSet
实现了Serializable
,所以支持序列化。HashSet
中存储的元素是无序的。HashSet
允许 null 值的元素。HashSet
不是线程安全的。
其中HashSet
的核心是通过基于HashMap
来实现的:
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
通过这个map
去实现诸如add
、remove
、clear
方法。
// 返回迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
// 大小
public int size() {
return map.size();
}
// 判断非空
public boolean isEmpty() {
return map.isEmpty();
}
// 是否包含某个元素
public boolean contains(Object o) {
return map.containsKey(o);
}
// 如果不存在添加的元素,则添加元素
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// 如果存在,则从此集合中删除对象
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
// 清除
public void clear() {
map.clear();
}
# TreeSet类
TreeSet
类依赖于 TreeMap
,它实际上是通过 TreeMap
实现的。TreeSet
中的元素是有序的,它是按自然排序或者用户指定比较器排序的 Set。具有以下特点:
TreeSet
通过继承AbstractSet
实现了NavigableSet
接口中的骨干方法。TreeSet
实现了Cloneable
,所以支持克隆。TreeSet
实现了Serializable
,所以支持序列化。TreeSet
中存储的元素是有序的。排序规则是自然顺序或比较器(Comparator
)中提供的顺序规则。TreeSet
不是线程安全的。
和HashSet
类似,内部的核心是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();
通过这个map
去实现其他核心方法:
public int size() {
return m.size();
}
public boolean isEmpty() {
return m.isEmpty();
}
public boolean contains(Object o) {
return m.containsKey(o);
}
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
public void clear() {
m.clear();
}
# LinkedHashSet类
LinkedHashSet
是按插入顺序排序的 Set。具有以下特点:
LinkedHashSet
通过继承HashSet
实现了Set
接口中的骨干方法。LinkedHashSet
实现了Cloneable
,所以支持克隆。LinkedHashSet
实现了Serializable
,所以支持序列化。LinkedHashSet
中存储的元素是按照插入顺序保存的。LinkedHashSet
不是线程安全的。
构造方法
LinkedHashSet
有三个构造方法,无一例外,都是调用父类 HashSet
的构造方法。
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
而这三个构造方法所调用的父类构造方法如下:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
相当于是创建了一个LinkedHashMap
,由于LinkedHashMap
实际上为一个双链表,所以LinkedHashSet
就是维护了一个双链表。由双链表的特性可以知道,它是按照元素的插入顺序保存的。所以,这就是 LinkedHashSet
中存储的元素是按照插入顺序保存的原理。
# EnumSet类
EnumSet
类定义如下:
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable {}
具有以下特点:
EnumSet
继承了AbstractSet
,所以有Set
接口中的骨干方法。EnumSet
实现了Cloneable
,所以支持克隆。EnumSet
实现了Serializable
,所以支持序列化。EnumSet
通过<E extends Enum<E>>
限定了存储元素必须是枚举值。EnumSet
没有构造方法,只能通过类中的static
方法来创建EnumSet
对象。EnumSet
是有序的。以枚举值在EnumSet
类中的定义顺序来决定集合元素的顺序。EnumSet
不是线程安全的。