jdk8源码:set子类

从AbstractSet继承来的子类有HashSet、LinkedHashSet、TreeSet等。

HashSet

持有一个HashMap引用,使用它的Entry来保存对象(key域指向我们真正保存的对象,value域指向同一个静态finalObject对象),因此HashSet元素不能重复,可以有一个null。不保证元素顺序(因为HashMap不保证元素顺序,且table数组会自动扩容,扩容时会以lo、hi算法移动链表上部分节点的存储位置)。使用的迭代器就是HashMap中成员内部类keySet使用的KeyIterator迭代器。非线程安全。

LinkedHashSet

由于继承自HashSet(且并未覆盖任何方法),所以基本继承了HashSet所有特性,只是持有的是LinkedHashMap的引用(数组保存每一条链表之外,节点还有before和after两个域将节点按照插入顺序构成双向链表),所以可以保证元素顺序。同样由于使用Entry的key存储对象,所以不重复,可以有一个null。非线程安全。

TreeSet

持有一个TreeMap的引用,使用他的Entry来保存对象(key域指向我们真正保存的对象,value域指向同一个静态finalObject对象),因为TreeMap的对象比较依赖于key的比较器,所以我们要保存的对象不能为null、且必须实现Comparable接口。由于TreeMap不保证插入顺序(因为红黑树的旋转和修建),但是保证某一个时刻所有元素的大小顺序(比较器指定比较方式),可以导出key、value、Entry的有序集合,所以TreeSet可以保持元素的大小顺序(比较器指定的排序方式)。非线程安全。

1.HashSet

         HashSet比较简单。首先HashSet从AbstractSet继承而来,相关实现接口源码如下:

public class HashSet<E> extends AbstractSet<E>  implements Set<E>, Cloneable, java.io.Serializable
{
}

        他的所有操作都是用HashMap对象实现的,保存到HashSet的对象实际上是保存为HashMap中节点Entry的key。所以HashSet元素不可重复、可以为null(null键在HashMap的table[0]位置)。成员申明如下:

    //保存节点数据
    //key域指向我们真正保存的对象
    //value域指向同一个静态不可变对象
    //HashSet保存对象和HashMap保存key的要求一样:不能重复,可以为null
    private transient HashMap<E,Object> map;

    //所有键值对的value
    private static final Object PRESENT = new Object();

       他的构造器其实也是基于HashMap的几个构造器,值得注意的是最后一个构造器会创建LinkedHashMap对象而不是HashMap对象。这个构造器是给LinkedHashSet使用的。其源码如下:

//构造器
    //默认容量16加载因子0.75创建HashMap
    public HashSet() {
        map = new HashMap<>();
    }
    //指定容量创建HashMap
    public HashSet(Collection<? extends E> c) {
    	//计算容量,这个容量保证集合c所有元素都插入table数组中也不会达到扩用阈值
        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
    //所以直接使用HashMap的公共导出方法keySet()取得key的Set集合
    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();
    }

        剩下的就是一些Object方法,源码如下:

    //Object方法
    @SuppressWarnings("unchecked")
    public Object clone() {
        try {
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        s.defaultWriteObject();
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());
        s.writeInt(map.size());
        for (E e : map.keySet())
            s.writeObject(e);
    }
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        int capacity = s.readInt();
        if (capacity < 0) {
            throw new InvalidObjectException("Illegal capacity: " +
                                             capacity);
        }
        float loadFactor = s.readFloat();
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        }
        int size = s.readInt();
        if (size < 0) {
            throw new InvalidObjectException("Illegal size: " +
                                             size);
        }
        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
                HashMap.MAXIMUM_CAPACITY);
        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));
        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }
    public Spliterator<E> spliterator() {
        return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
    }

2.LinkedHashSet

        LinkedHashSet相比更加简单,继承自HashMap,基于LinkedHashMap实现的整个类文件短短40行代码。类申明源码如下:

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

        类文件仅仅包含几个构造器,调用的HashSet的构造器,创建一个LinkedHashMap对象,从父类继承的map成员引用这个新创建的对象。源码如下:

	//构造器
	//底层均是调用HashSet的构造器HashSet(initialCapacity,loadFactor,dummy) 
	//会创建一个LinkedHashMap对象
	//从父类继承的成员map指向上述对象
	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);
	}

        除此之外并未覆盖任何父类方法,但是他是怎么支持链表操作的呢,可以查看其父类HashSet方法调用链,源码如下:

	//HashSet的add(e)
	public boolean add(E e) {
	    return map.put(e, PRESENT)==null;
	}
	
	//HashMap的put(key,value)
	public V put(K key, V value) {
	    return putVal(hash(key), key, value, false, true);
	}
	//HashMap的putVAl(hash,key,value,onlyIfAbsent,evict)
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
		//省略
		//这个方法记录了该节点在被操作之后(比如添加到map)需要执行的操作
		afterNodeAccess(e);
		//
		afterNodeInsertion(evict);
		return null;
	}
	//HashMap的afterNodeAccess(e)
	void afterNodeInsertion(boolean evict) { 
		//HashMap里没有任何操作
	}
	//LinkedHashMap的afterNodeAccess(e)
    void afterNodeAccess(Node<K,V> e) { 
    	//省略
        //这里将被访问的节点添加到了双链表的尾部
    }

        可以看到,底层基于LinkedHashMap来调用从父类继承的方法,父类HashMap的基础方法实现中已经考虑到了后续子类的扩展,于是利用方法自用性,调用了一个不做任何处理的函数。如果是HashMap对象来调用基础方法,其方法内部调用的扩展方法不做任何处理,如果是LinkedHashMap对象来调用基础方法,就可以自己指定如何进行扩展。我们再看迭代器实现,源码如下:

//LinkedHashSet没有覆盖HashSet的迭代器方法,HashSet的iterator()方法如下:
public Iterator<E> iterator() {
    return map.keySet().iterator();
}
//LinkedHashMap的keySet()方法如下:
public Set<K> keySet() {
    Set<K> ks;
    //LinkedKeySet是LinkedHashMap成员内部类实现
    return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
}
//LinkedKeySet成员内部类如下:
final class LinkedKeySet extends AbstractSet<K> {
    //省略
    public final Iterator<K> iterator() {
    	//LinkedKeyIterator是迭代器的内部类实现
        return new LinkedKeyIterator();
    }
}
//LinkedKeyIterator成员内部类如下:
final class LinkedKeyIterator extends LinkedHashIterator implements Iterator<K> {
		public final K next() { 
			//next返回的是当前节点的after域指向的节点,即使用双链表的方式迭代
			return nextNode().getKey();
			}
}

        我们可以看到,虽然并没有覆盖父类的方法,但是利用父类引用子类对象,使用运行时动态绑定调用子类方法,利用继承的层级关系和多态很方便的实现了LinkedHashSet的全部功能。

3.TreeSet

        TreeSet持有一个TreeMap对象的引用,所有操作都基于TreeMap来实现。类文件代码仅仅200多行。首先查看他的接口 NavigableSet<E>,这个接口继承了SortedSet<E>接口以提供更详细的有序集合的相关操作。源码如下:

public interface NavigableSet<E> extends SortedSet<E> {
   
	//返回的是集合中比参数元素更小的所有元素中最大的那个
    E lower(E e);
    //返回的是集合中小于等于参数元素的所有元素中最大的那个
    E floor(E e);
    //返回的是集合中大于等于参数元素的所有元素中最小的那个
    E ceiling(E e);
    //返回的是集合中大于参数元素E pollLast();的所有元素中最小的那个
    E higher(E e);
    //将第一个元素踢出并返回
    E pollFirst();
    //将最后一个元素踢出并返回
    E pollLast();
    Iterator<E> iterator();
    //得到一个倒序排列的本集合实例
    NavigableSet<E> descendingSet();
    //返回的是倒序迭代器
    Iterator<E> descendingIterator();
    //将本集合截取的方法,两个boolean参数表示是否包含被截取的头元素和尾元素。
    NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                           E toElement,   boolean toInclusive);
    //返回的是参数元素之前的元素集合,boolean参数表示参数元素是否被包含。
    NavigableSet<E> headSet(E toElement, boolean inclusive);
    //返回的是参数元素之后的元素集合,boolean参数表示参数元素是否被包含。
    NavigableSet<E> tailSet(E fromElement, boolean inclusive);
    //截取集合
    SortedSet<E> subSet(E fromElement, E toElement);
    //截取集合
    SortedSet<E> headSet(E toElement);
    //截取集合
    SortedSet<E> tailSet(E fromElement);
}

        查看TreeSet类申明,源码如下:

public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable
{
}

        查看其成员、构造器。可以看到包含一个TreeMap对象的引用,他的所有构造器其实都是对TreeMap的不同构造器的封装。源码如下:

//NavigableMap<K,V>子类,引用一个TreeMap
    private transient NavigableMap<E,Object> m;

    //TreeMap中所有value均使用这个对象
    private static final Object PRESENT = new Object();

    //构造器
    TreeSet(NavigableMap<E,Object> m) {
    	//指定TreeMap创建TreeSet
        this.m = m;
    }
    public TreeSet() {
    	//自然顺序创建TreeMap,再创建TreeSet
        this(new TreeMap<E,Object>());
    }
    public TreeSet(Comparator<? super E> comparator) {
    	//指定排序方式创建TreeMap,再创建TreeSet
        this(new TreeMap<>(comparator));
    }
    public TreeSet(Collection<? extends E> c) {
    	//创建默认TreeMap和TreeSet,再将集合元素全部添加到TreeMap中
        this();
        addAll(c);
    }
    public TreeSet(SortedSet<E> s) {
    	//通过有序Set指定的排序方法、以及它的所有元素创建TreeMap、TreeSet
        this(s.comparator());
        addAll(s);
    }

        其他方法比较简单,基本上所有接口方法的实现底层都是调用的TreeMap对象的相关方法来实现。源码如下:

 //批量添加
    public  boolean addAll(Collection<? extends E> c) {
        //限定c的为三种类型之一
        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);
    }
    
    //迭代器
    public Iterator<E> iterator() {
        return m.navigableKeySet().iterator();
    }
    //降序迭代器
    public Iterator<E> descendingIterator() {
        return m.descendingKeySet().iterator();
    }
    //并行迭代器
    public Spliterator<E> spliterator() {
        return TreeMap.keySpliteratorFor(m);
    }
    

    //返回有序(降序)Set
    public NavigableSet<E> descendingSet() {
        return new TreeSet<>(m.descendingMap());
    }

    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();
    }

    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                                  E toElement,   boolean toInclusive) {
        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
                                       toElement,   toInclusive));
    }

    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
        return new TreeSet<>(m.headMap(toElement, inclusive));
    }

    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
        return new TreeSet<>(m.tailMap(fromElement, inclusive));
    }

    public SortedSet<E> subSet(E fromElement, E toElement) {
        return subSet(fromElement, true, toElement, false);
    }

    public SortedSet<E> headSet(E toElement) {
        return headSet(toElement, false);
    }

    public SortedSet<E> tailSet(E fromElement) {
        return tailSet(fromElement, true);
    }

    public Comparator<? super E> comparator() {
        return m.comparator();
    }

    public E first() {
        return m.firstKey();
    }

    public E last() {
        return m.lastKey();
    }

    public E lower(E e) {
        return m.lowerKey(e);
    }

    public E floor(E e) {
        return m.floorKey(e);
    }

    public E ceiling(E e) {
        return m.ceilingKey(e);
    }

    public E higher(E e) {
        return m.higherKey(e);
    }

    public E pollFirst() {
        Map.Entry<E,?> e = m.pollFirstEntry();
        return (e == null) ? null : e.getKey();
    }

    public E pollLast() {
        Map.Entry<E,?> e = m.pollLastEntry();
        return (e == null) ? null : e.getKey();
    }

    @SuppressWarnings("unchecked")
    public Object clone() {
        TreeSet<E> clone;
        try {
            clone = (TreeSet<E>) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }

        clone.m = new TreeMap<>(m);
        return clone;
    }

   
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden stuff
        s.defaultWriteObject();

        // Write out Comparator
        s.writeObject(m.comparator());

        // Write out size
        s.writeInt(m.size());

        // Write out all elements in the proper order.
        for (E e : m.keySet())
            s.writeObject(e);
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden stuff
        s.defaultReadObject();

        // Read in Comparator
        @SuppressWarnings("unchecked")
            Comparator<? super E> c = (Comparator<? super E>) s.readObject();

        // Create backing TreeMap
        TreeMap<E,Object> tm = new TreeMap<>(c);
        m = tm;

        // Read in size
        int size = s.readInt();

        tm.readTreeSet(size, s, PRESENT);
    }










猜你喜欢

转载自blog.csdn.net/qq_34448345/article/details/79844729