根据之前讲HashSet和HashMap的关系,TreeSet和TreeMap的关系,我们也能猜测出来LinkedHashSet肯定也是通过LinkedHashMap实现的,只是LinkedHashMap所有键值对的value都是一个特定的值,所有的key便组成了LinkedHashSet的所有集合元素,并能保证所有的集合元素按插入有序。LinkedHashSet类的继承关系如下图所示:
可以看到,LinkedHashSet实现了Set接口,继承了HashSet类。HashSet是基于HashMap实现的,HashSet中的方法操作的其实是内部的HashMap实例。如果可以让HashSet中的方法操作LinkedHashMap实例,那么就能轻松的实现LinkedHashSet了。其实Java API中也是这样实现的,下面会详细讲述。
1. 使用示例
public static void main(String[] args) {
Set<Integer> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(1);
linkedHashSet.add(5);
linkedHashSet.add(3);
for (Integer item : linkedHashSet) {
System.out.println(item);
}
}
运行结果:
1
5
3
LinkedHashSet中的元素按插入有序。
2. 方法说明
LinkedHashSet继承了HashSet,实现了Set接口,除构造函数之外的方法,都实现自Set接口。
2.1 构造方法
S.N. | 方法 | 说明 |
---|---|---|
1 | public LinkedHashSet() | 默认构造函数,构造容量为16,负载因子为0.75的空LinkedHashSet |
2 | public LinkedHashSet(int initialCapacity) | 构造容量为initialCapacity,负载因子为0.75的空LinkedHashSet |
3 | public LinkedHashSet(int initialCapacity, float loadFactor) | 构造容量为initialCapacity,负载因子为loadFactor的空LinkedHashSet |
4 | public LinkedHashSet(Collection<? extends E> c) | 通过Collection对象构造LinkedHashSet |
2.2 Set接口
S.N. | 方法 | 说明 |
---|---|---|
1 | boolean add(E e) | 向Set中添加一个元素 |
2 | boolean addAll(Collection<? extends E> c) | 将Collection中的元素添加到Set中 |
3 | boolean contains(Object o) | 判断Set中是否包含o元素 |
4 | boolean containsAll(Collection<?> c) | 判断Collection中的元素是否全部存在于Set中 |
5 | boolean equals(Object o) | equals方法 |
6 | int hashCode() | hashCode方法 |
7 | boolean isEmpty() | 判断Set是否为空 |
8 | Iterator<E> iterator() | 返回Set的单向Iterator迭代器 |
9 | boolean remove(Object o) | 删除Set中的元素o |
10 | boolean removeAll(Collection<?> c) | 删除Set中包含的Collection的所有元素,如果c也为Set,表示求差集 |
11 | boolean retainAll(Collection<?> c) | 保留Set中包含的Collection的所有元素,如果c也为Set,表示求交集 |
12 | int size() | 返回Set元素个数 |
13 | default Spliterator<E> spliterator() | 返回Set的并行流Spliterator迭代器 |
14 | Object[] toArray() | Set转Object[]数组 |
15 | <T> T[] toArray(T[] a) | Set转特定类型数组 |
3. 实现源码分析
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);
}
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类的全部实现,看着不免有些懵逼。为什么只有构造函数,说好的通过LinkedHashMap实现的呢,连LinkedHashMap的影子都没看到。其实奥秘就在那个super(来自HashSet的构造函数)中,我们来看一下HashSet中这个构造函数的实现:
/**
* 构建一个空的按插入有序的LinkedHashMap,LinkedHashMap容量为initialCapacity,负载因子为loadFactor
*
* @param initialCapacity LinkedHashMap容量
* @param loadFactor LinkedHashMap负载因子
* @param dummy 忽略,仅用于与其他构造函数区分
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
//调用的是LinkedHashMap构造函数,返回LinkedHashMap实例,map的运行时类型为LinkedHashMap
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
所以,之后所有HashSet中所有方法对于map的操作,操作的都是LinkedHashMap实例,所以可以保证LinkedHashSet中元素按插入有序。
4. LinkedHashSet特点
LinkedHashSet实现了Set接口,内部是通过LinkedHashMap实现的,这也决定了HashSet有如下特点:
- LinkedHashSet中可以保证没有重复元素
- 添加、删除、判断元素是否存在,效率很高,时间复杂度为O(1)。
- LinkedHashSet可以保证元素按插入有序
参考链接:
- Java API源码