Javaコレクション6:HashSet、LinkedHashSet、TreeSet


一:HashSet
public class HashSet<E> extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
  • HashSetは、AbstractSetクラスに継承され、このインタフェースを実装するために必要なワークロードを最小限に抑えるために、Setインタフェースのスケルトン実装を提供する.
  • は、内部要素が無秩序であり、要素が繰り返してはならないことを示すSetインタフェースを実装する.
  • はCloneableインタフェースを実装し、コピー可能であることを示す.
  • はSerializableインターフェースを実装し、シーケンス化可能であることを示す.

  • HashSet内部はHashMapのkeyで要素を保存しています
    	//  HashMap Key   HashSet     。
    	private transient HashMap<E,Object> map;
    
        //    Object    HashMap value
        private static final Object PRESENT = new Object();
    

    コンストラクタ
       /**
    	*       hashSet,            HashMap,          16     0.75。
    	*/
    	public HashSet() {
         
            map = new HashMap<>();
        }
    
        /**
         *                  。HashMap         (0.75)       
         *              。
         */
        public HashSet(Collection<? extends E> c) {
         
            map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
            addAll(c);
        }
    
        /**
         *     initialCapacity loadFactor      HashSet
         *                 HashMap。
         */
        public HashSet(int initialCapacity, float loadFactor) {
         
            map = new HashMap<>(initialCapacity, loadFactor);
        }
    
        /**
         *     initialCapacity      HashSet。
         *                loadFactor 0.75      HashMap。
         */
        public HashSet(int initialCapacity) {
         
            map = new HashMap<>(initialCapacity);
        }
    
        /**
         *     initialCapacity loadFactor             。
         *            ,     ,      LinkedHashSet   。
         *                 LinkedHashMap     。
         */
        HashSet(int initialCapacity, float loadFactor, boolean dummy) {
         
            map = new LinkedHashMap<>(initialCapacity, loadFactor);
        }
    

    反復器インプリメンテーション:keyの集合を返す反復器
        public Iterator<E> iterator() {
         
            return map.keySet().iterator();
        }
    
    	/**
         *    set       (set   )。
         *       HashMap size()    Entry   ,    Set      。
         */
        public int size() {
         
            return map.size();
        }
    
        /**
         *    set       ,   true。 
         *       HashMap isEmpty()   HashSet    。
         */
        public boolean isEmpty() {
         
            return map.isEmpty();
        }
    
        /**
         *    set      ,   true。
         *       HashMap containsKey        key。
         */
        public boolean contains(Object o) {
         
            return map.containsKey(o);
        }
    
        /**
         *    set         ,       。
         *            key  HashMap。
         */
        public boolean add(E e) {
         
            return map.put(e, PRESENT)==null;
        }
    
        /**
         *           set ,     。 
         *       HashMap remove      Entry。
         */
        public boolean remove(Object o) {
         
            return map.remove(o)==PRESENT;
        }
    
        /**
         *   set       。
         *       HashMap clear    Entry     。
         */
        public void clear() {
         
            map.clear();
        }
    
        /**
         *    HashSet       :           。 
         *       HashMap clone()  ,  HashMap     ,    HashSet 。
         */
        @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 {
         
            // Write out any hidden serialization magic
            s.defaultWriteObject();
    
            // Write out HashMap capacity and load factor
            s.writeInt(map.capacity());
            s.writeFloat(map.loadFactor());
    
            // Write out size
            s.writeInt(map.size());
    
            // Write out all elements in the proper order.
            for (E e : map.keySet())
                s.writeObject(e);
        }
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
         
            // Read in any hidden serialization magic
            s.defaultReadObject();
    
            // Read capacity and verify non-negative.
            int capacity = s.readInt();
            if (capacity < 0) {
         
                throw new InvalidObjectException("Illegal capacity: " +
                                                 capacity);
            }
    
            // Read load factor and verify positive and non NaN.
            float loadFactor = s.readFloat();
            if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
         
                throw new InvalidObjectException("Illegal load factor: " +
                                                 loadFactor);
            }
    
            // Read size and verify non-negative.
            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);
            SharedSecrets.getJavaOISAccess()
                         .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity));
    
            // Create backing HashMap
            map = (((HashSet<?>)this) instanceof LinkedHashSet ?
                   new LinkedHashMap<E,Object>(capacity, loadFactor) :
                   new HashMap<E,Object>(capacity, loadFactor));
    
            // Read in all elements in the proper order.
            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);
        }
    
  • HashSetは機能を制限したHashMapであるため,HashMapの実現原理を知ると,このHashSetは自然に
  • に通じる.
  • HashSetに保存するオブジェクトについては、主にequalsメソッドとhashCodeメソッドを正しく書き換えて、Setオブジェクトに入れる一意性
  • を保証する.
  • は、Setが重複する要素に対して入れないとはいえ、むしろそのまま下位のMapがそのまま原値を代える(このSetのputメソッドの戻り値は面白い)
  • HashSetはget()メソッドを提供していないが、HashMapと同様に、Set内部は無秩序であり、反復的に
  • しか得られないことを望む.
    二:LinkedHashSet
    LinkedHashSetはHashSetの「拡張バージョン」であり、HashSetは順序に関係なく、LinkedHashSetは「挿入順序」を維持します.HashSet内部ではHashMapオブジェクトを使用して要素を格納し、LinkedHashSet内部ではLinkedHashMapオブジェクトを使用して要素を格納および処理します.ソースコードは以下の通りです.
    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はHashSetに継承され、4つのコンストラクション関数のみが含まれており、この4つのコンストラクション関数は同じ親クラスのコンストラクション関数を呼び出していることに気づくことができます.親の構造関数を見てみましょう.
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
         
            map = new LinkedHashMap<>(initialCapacity, loadFactor);
        }
    

    このコンストラクション関数には,初期容量,負荷因子,booleanタイプのダミー値(タグとして,何の役にも立たないパラメータ)などのパラメータが必要である.このダミーパラメータは,この構造関数とHashSetの他の初期容量と負荷因子パラメータを持つ構造関数を区別するために用いられるだけである.このコンストラクション関数の内部にはLinkedHashMapオブジェクトが初期化されており、このオブジェクトはLinkedHashSetによってその要素を格納するために適切に使用されます.LinkedHashSetには独自のメソッドはなく、すべてのメソッドが親HashSetから継承されているため、LinkedHashSetに対するすべての操作方法はHashSetに対する操作のようになっています.唯一の違いは、内部で異なるオブジェクトを使用して要素を格納することです.HashSetでは、挿入された要素はHashMapのキーとして保存され、LinkedHashSetではLinkedHashMapのキーと見なされる.
    三:TreeSet
    TreeMapは秩序化された二叉木であることを知っています.それでは、同じTreeSetも秩序化されており、その役割は秩序化されたSet集合を提供することです.TreeSetの要素は、2つのソート方法をサポートします.自然ソートまたはTreeSetの作成時に提供されるComparatorに基づいてソートします.これは使用する構造方法によって異なります.ソースコードによってTreeSetベースAbstractSetが知られており、NavigableSet、Cloneable、Serializableインタフェースが実現されています.ここで、AbstractSetは、Setインタフェースの中堅実装を提供し、このインタフェースを実装するために必要な作業を最小限に抑える.NavigableSetは拡張されたSortedSetであり、所与の検索ターゲットに最も近い一致を報告するナビゲーション方法を有し、これは一連のナビゲーション方法をサポートすることを意味する.たとえば、指定したターゲットと最も一致するアイテムを検索します.Cloneableはクローンをサポートし、Serializableはシーケンス化をサポートします.
    public class TreeSet<E> extends AbstractSet<E>
        implements NavigableSet<E>, Cloneable, java.io.Serializable
    {
         
        //  NavigableMap   TreeSet  
        private transient NavigableMap<E,Object> m;
    
        //  NavigableMap          
        private static final Object PRESENT = new Object();
    
        /**
         *       NavigableMap   。
         */
        TreeSet(NavigableMap<E,Object> m) {
         
            this.m = m;
        }
    
        /**
         *        TreeSet,             。                 Comparable  。 
         *   ,                                  ,  add       
         * ClassClassException。
         */
        public TreeSet() {
         
            this(new TreeMap<E,Object>());
        }
    
        /**
         *        TreeSet,            。                          
         *                    ,  add     ClassCastException。
         */
        public TreeSet(Comparator<? super E> comparator) {
         
            this(new TreeMap<>(comparator));
        }
    
        /**
         *      TreeSet,            ,                。 
         *                 Comparable  。   ,              
         */
        public TreeSet(Collection<? extends E> c) {
         
            this();
            addAll(c);
        }
    
        /**
         *                          TreeSet。
         */
        public TreeSet(SortedSet<E> s) {
         
            this(s.comparator());
            addAll(s);
        }
    
        /**
         *                。
         */
        public Iterator<E> iterator() {
         
            return m.navigableKeySet().iterator();
        }
    
        /**
         *                。
         */
        public Iterator<E> descendingIterator() {
         
            return m.descendingKeySet().iterator();
        }
    
        /**
         * @since 1.6
         */
        public NavigableSet<E> descendingSet() {
         
            return new TreeSet<>(m.descendingMap());
        }
    
        /**
         *            (  )。           。
         */
        public int size() {
         
            return m.size();
        }
    
        /**
         *   TreeSet    
         */
        public boolean isEmpty() {
         
            return m.isEmpty();
        }
    
        /**
         *   TreeSet      (o)
         */
        public boolean contains(Object o) {
         
            return m.containsKey(o);
        }
    
        /**
         *   e TreeSet 
         */
        public boolean add(E e) {
         
            return m.put(e, PRESENT)==null;
        }
    
        /**
         *   TreeSet    o
         */
        public boolean remove(Object o) {
         
            return m.remove(o)==PRESENT;
        }
    
        /**
         *   TreeSet
         */
        public void clear() {
         
            m.clear();
        }
    
        /**
         *    c         TreeSet 
         */
        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);
        }
    
        /**
         *     Set,      TreeMap subMap()   。
         */
        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                                      E toElement,   boolean toInclusive) {
         
            return new TreeSet<>(m.subMap(fromElement, fromInclusive,
                                           toElement,   toInclusive));
        }
    
        /**
         *   Set   ,   :    toElement。
         * inclusive     toElement   
         */
        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
         
            return new TreeSet<>(m.headMap(toElement, inclusive));
        }
    
        /**
         *   Set   ,   : fromElement   。
         * inclusive     fromElement   
         */
        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
         
            return new TreeSet<>(m.tailMap(fromElement, inclusive));
        }
    
        /**
         *    Set。   : fromElement(  ) toElement(   )。
         */
        public SortedSet<E> subSet(E fromElement, E toElement) {
         
            return subSet(fromElement, true, toElement, false);
        }
    
        /**
         *   Set   ,   :    toElement(   )。
         */
        public SortedSet<E> headSet(E toElement) {
         
            return headSet(toElement, false);
        }
    
        /**
         *   Set   ,   : fromElement   (   )。
         */
        public SortedSet<E> tailSet(E fromElement) {
         
            return tailSet(fromElement, true);
        }
    
        //  Set    
        public Comparator<? super E> comparator() {
         
            return m.comparator();
        }
    
        /**
         *   Set      
         */
        public E first() {
         
            return m.firstKey();
        }
    
        /**
         *   Set       
         */
        public E last() {
         
            return m.lastKey();
        }
    
        // NavigableSet API methods
    
        /**
         *   Set   e     
         */
        public E lower(E e) {
         
            return m.lowerKey(e);
        }
    
        /**
         *  Set   /  e     
         */
        public E floor(E e) {
         
            return m.floorKey(e);
        }
    
        /**
         *  Set   /  e     
         */
        public E ceiling(E e) {
         
            return m.ceilingKey(e);
        }
    
        /**
         *   Set   e     
         */
        public E higher(E e) {
         
            return m.higherKey(e);
        }
    
        /**
         *        ,      TreeMap   。
         */
        public E pollFirst() {
         
            Map.Entry<E,?> e = m.pollFirstEntry();
            return (e == null) ? null : e.getKey();
        }
    
        /**
         *         ,      TreeMap   。
         */
        public E pollLast() {
         
            Map.Entry<E,?> e = m.pollLastEntry();
            return (e == null) ? null : e.getKey();
        }
    
        /**
         *    TreeSet,   Object  
         */
        @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;
        }
    
        /**
         * java.io.Serializable     
         * TreeSet “   、  ,      ”        
         */
        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);
        }
    
        /**
         *  java.io.Serializable     :        
         *    TreeSet “   、  、      ”    
         */
        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);
        }
        public Spliterator<E> spliterator() {
         
            return TreeMap.keySpliteratorFor(m);
        }
    
        private static final long serialVersionUID = -2479143000061671589L;
    }
    

    TreeSetは実際にはTreeMapで実現されている.TreeSetを構築するとパラメータを持たないコンストラクション関数を使用する場合、TreeSetは自然比較器を使用します.ユーザがカスタムコンパレータを使用する必要がある場合は、コンパレータ付きパラメータを使用する必要があります.