coding……
但行好事 莫问前程

Java编程拾遗『LinkedHashSet』

根据之前讲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可以保证元素按插入有序

参考链接:

  1. Java API源码

 

赞(1) 打赏
Zhuoli's Blog » Java编程拾遗『LinkedHashSet』
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址