Java集合框架——Set

前言

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====================
河北
河南
北京
广州

猜你喜欢

转载自blog.csdn.net/qgnczmnmn/article/details/108584322