The problem

(1) Does TreeSet really use TreeMap to store elements?

(2) Is TreeSet in order?

(3) What is the difference between TreeSet and LinkedHashSet?

Introduction to the

The underlying TreeSet is a Set implemented in TreeMap, so it is ordered and also non-thread-safe.

Source code analysis

After studying HashSet and LinkedHashSet, we have basically mastered the Set implementation.

So, also no nonsense, directly on the source code:

package java.util;

// TreeSet implements the NavigableSet interface, so it is ordered
public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable.java.io.Serializable
{
    // Elements are stored in NavigableMap
    // Note that it is not necessarily TreeMap
    private transient NavigableMap<E,Object> m;

    // A virtual element that is stored as a value in the map
    private static final Object PRESENT = new Object();

    // Store elements directly using the NavigableMap passed in
    // This is not a deep copy. If there are additions or deletions in the external map, they will be reflected here
    // Also, this method is not public, indicating that it can only be used by the same package
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

    // Use TreeMap to initialize
    public TreeSet(a) {
        this(new TreeMap<E,Object>());
    }

    // Initialize using TreeMap with comparator
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

    // Add all the elements in collection C to the TreeSet
    public TreeSet(Collection<? extends E> c) {
        this(a); addAll(c); }// Add all the elements in SortedSet to TreeSet
    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

    / / the iterator
    public Iterator<E> iterator(a) {
        return m.navigableKeySet().iterator();
    }

    // Reverse iterator
    public Iterator<E> descendingIterator(a) {
        return m.descendingKeySet().iterator();
    }

    // Return a new TreeSet in reverse order
    public NavigableSet<E> descendingSet(a) {
        return new TreeSet<>(m.descendingMap());
    }

    // Number of elements
    public int size(a) {
        return m.size();
    }

    // Check whether it is null
    public boolean isEmpty(a) {
        return m.isEmpty();
    }

    // Determine whether an element is included
    public boolean contains(Object o) {
        return m.containsKey(o);
    }

    // Add the element and call map's put() method with value PRESENT
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
    
    // Delete elements
    public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }

    // Clear all elements
    public void clear(a) {
        m.clear();
    }

    // Add all the elements in collection C
    public  boolean addAll(Collection<? extends E> c) {
        // If certain conditions are met, the addAllForTreeSet() method of TreeMap is directly called to add elements
        if (m.size()==0 && c.size() > 0 &&
            c instanceof SortedSet &&
            m instanceofTreeMap) { 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; }}// If the above conditions are not met, addAll() of the parent class is called to add elements one by one through a traversal
        return super.addAll(c);
    }

    // Subset (method in NavigableSet)
    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                                  E toElement,   boolean toInclusive) {
        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
                                       toElement,   toInclusive));
    }
    
    // set (NavigableSet)
    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
        return new TreeSet<>(m.headMap(toElement, inclusive));
    }

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

    // subset (method in SortedSet interface)
    public SortedSet<E> subSet(E fromElement, E toElement) {
        return subSet(fromElement, true, toElement, false);
    }

    // header set (method in SortedSet interface)
    public SortedSet<E> headSet(E toElement) {
        return headSet(toElement, false);
    }
    
    // tail set (SortedSet method)
    public SortedSet<E> tailSet(E fromElement) {
        return tailSet(fromElement, true);
    }

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

    // Return the smallest element
    public E first(a) {
        return m.firstKey();
    }
    
    // Return the largest element
    public E last(a) {
        return m.lastKey();
    }

    // Return the largest element less than e
    public E lower(E e) {
        return m.lowerKey(e);
    }

    // Returns the largest element less than or equal to e
    public E floor(E e) {
        return m.floorKey(e);
    }
    
    Return the smallest element greater than or equal to e
    public E ceiling(E e) {
        return m.ceilingKey(e);
    }
    
    Return the smallest element greater than e
    public E higher(E e) {
        return m.higherKey(e);
    }
    
    // Pop up the smallest element
    public E pollFirst(a) { Map.Entry<E,? > e = m.pollFirstEntry();return (e == null)?null : e.getKey();
    }

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

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

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

    // serialize the write method
    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);
    }

    // Serialize the write method
    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);
    }

    // A separable iterator
    public Spliterator<E> spliterator(a) {
        return TreeMap.keySpliteratorFor(m);
    }

    // serialize the ID
    private static final long serialVersionUID = -2479143000061671589L;
}
Copy the code

The source code is relatively simple, the basic is to call map corresponding methods.

conclusion

(1) TreeSet uses NavigableMap to store elements.

(2) TreeSet is ordered;

(3) TreeSet is non-thread-safe;

(4) TreeSet implements NavigableSet, and NavigableSet inherits from SortedSet;

(5) TreeSet implements SortedSet interface; (Tong Brother was asked the difference between a TreeSet and a SortedSet when he was young.)

eggs

(1) From previous learning, we know that TreeSet and LinkedHashSet are both ordered, so how are they different?

LinkedHashSet does not implement SortedSet interface, and its orderness mainly depends on the orderness of LinkedHashMap, so its orderness refers to the orderness guaranteed by insertion order;

TreeSet implements the SortedSet interface, which relies mainly on the ordering of NavigableMap, which in turn inherits from the SortedMap. The ordering of this interface refers to the order guaranteed by the natural ordering of keys. The natural ordering of keys can be implemented either by the key implementing the Comparable interface or by the constructor passing in the Comparator.

(2) Does TreeSet really use TreeMap to store elements?

TreeSet actually uses NavigableMap to store elements. Most of the time the map is TreeMap, but not all of the time.

Because one constructor is TreeSet(NavigableMap

m), and this is a non-public method, we can see that this constructor is used in our own class, such as the following:
,object>

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

The tailMap() method calls TreeMap:

    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
        return new AscendingSubMap<>(this.false, fromKey, inclusive,
                                     true.null.true);
    }
Copy the code

As you can see, AscendingSubMap is returned. What is the inheritance chain for this class?

As you can see, this class does not inherit TreeMap, but you can see from the source code analysis that this class is a combination of TreeMap. It is also related to TreeMap, but not inherited.

So the underlying TreeSet is not implemented entirely using TreeMap, but rather NavigableMap.


Welcome to pay attention to my public number “Tong Elder brother read source code”, view more source code series articles, with Tong elder brother tour the ocean of source code.