zoukankan      html  css  js  c++  java
  • 集合类源码(八)Collection之Set(HashSet, LinkedHashSet, TreeSet,ConcurrentSkipListSet)

    HashSet

    先看一下成员变量

    // 由此可见内部存储是一个HashMap
    private transient HashMap<E,Object> map;
    
    private static final Object PRESENT = new Object();
    
    public HashSet() { map = new HashMap<>(); }

    add方法

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    仅仅是把新元素作为key,一个事先初始化好的空Object对象作为value,存入HashMap。

    同理,contains方法和remove方法都是调用HashMap的方法

    public boolean contains(Object o) {
        return map.containsKey(o);
    }
    
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

    HashSet实现很简单,完全基于HashMap。

    LinkedHashSet

    先来看继承关系,继承了HashSet

    public class LinkedHashSet<E>
        extends HashSet<E>
        implements Set<E>, Cloneable, java.io.Serializable

    本身也没有提供相关CRUD方法

     来看下构造方法

    public LinkedHashSet() {
        // 调用的父类的方法
        super(16, .75f, true);
    }
    
    // 父类(HashSet)构造方法
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        // 和HashSet区别在于new了一个LinkedHashMap
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

    这个构造方法是一个包私有的,仅仅提供给LinkedHashSet使用。

    LinkedHashSet的实现基于LinkedHashMap

    TreeSet

    到这里,不用看也能知道,TreeSet的实现基于TreeMap....

    来看成员变量

    private transient NavigableMap<E,Object> m;
    
    // 人家官方管这个Map中value的默认值叫做“哑值”
    private static final Object PRESENT = new Object();
    
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
    
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

    而add、contains、remove等方法也不必解释了

    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
    
    public boolean contains(Object o) {
        return m.containsKey(o);
    }
    
    public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }

    ConcurrentSkipListSet

    虽然这个名字很长,人家也是线程安全的Set,但是,依然依托于Map的具体实现类

    // 内部存储结构
    private final ConcurrentNavigableMap<E,Object> m;
    
    // 构造方法
    public ConcurrentSkipListSet() {
        m = new ConcurrentSkipListMap<E,Object>();
    }
    
    // add
    public boolean add(E e) {
        return m.putIfAbsent(e, Boolean.TRUE) == null;
    }
    
    // contains
    public boolean contains(Object o) {
        return m.containsKey(o);
    }
    
    // remove
    public boolean remove(Object o) {
        return m.remove(o, Boolean.TRUE);
    }

    与前面不同的是,ConcurrentSkipListSet内部Map的value值永远是一个  Boolean.TRUE

    优点:

    1. 基于跳表实现,查找效率高

    2. 线程安全

    CopyOnWriteArraySet

    这里呢,就不是基于Map的了,毕竟没有 CopyOnWriteArrayMap 这个集合类。虽然没有相关Map实现,但是是不是有一个 CopyOnWriteArrayList

    private final CopyOnWriteArrayList<E> al;
    
    /**
     * Creates an empty set.
     */
    public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<E>();
    }

    那是怎样去重的呢?

    public boolean add(E e) {
        // addIfAbsent:如果没有则添加,就是这样来保证无重复元素的
        return al.addIfAbsent(e);
    }

    其它都是直接调用其内部数据结构的方法

    public boolean contains(Object o) {
        return al.contains(o);
    }
    
    public boolean remove(Object o) {
        return al.remove(o);
    }

    总结:

    Set旗下的集合一般都是站在Map集合的肩膀上的,懂了Map,就懂了Set

    关于有序和无序:

    0. 无序:HashSet

    1. 按照自然顺序排序的:TreeSet、ConcurrentSkipListSet

    2. 按照添加顺序排序的:LinkedHashSet、CopyOnWriteArraySet

    测试程序

    public static void main(String[] args) throws Exception {
         deal(new HashSet<>());
         deal(new LinkedHashSet<>());
         deal(new TreeSet<>());
         deal(new ConcurrentSkipListSet<>());
         deal(new CopyOnWriteArraySet<>());
    }
    private static void deal(Set<String> set){
        set.add("s1");
        set.add("s9");
        set.add("s3");
        set.add("s5");
        set.add("s7");
        set.add("s2");
        set.add("s8");
        System.out.println(set.getClass().getName() + ":" + set);
    }

    结果:

    java.util.HashSet:[s3, s5, s7, s8, s9, s1, s2]
    java.util.LinkedHashSet:[s1, s9, s3, s5, s7, s2, s8]
    java.util.TreeSet:[s1, s2, s3, s5, s7, s8, s9]
    java.util.concurrent.ConcurrentSkipListSet:[s1, s2, s3, s5, s7, s8, s9]
    java.util.concurrent.CopyOnWriteArraySet:[s1, s9, s3, s5, s7, s2, s8]
  • 相关阅读:
    HDOJ1203 I NEED A OFFER!
    在.NET上进行线性代数等科学计算 (转)
    Autodesk布道GIS新理念
    Arcmap中将点图层的样式修改为自定义的图片(转)
    NASA从太空发射激光,制作地球森林高度地图
    C#获取cpu序列号,硬盘ID,网卡MAC地址
    Fortress
    ArcGIS Engine开发-自定义图层类型(转)
    学术会议网站列表
    网络疯传IT男女标配图
  • 原文地址:https://www.cnblogs.com/LUA123/p/11928908.html
Copyright © 2011-2022 走看看