美文网首页java collectionJava学习笔记
Java 集合 HashSet VS LinkedHashSet

Java 集合 HashSet VS LinkedHashSet

作者: 专职跑龙套 | 来源:发表于2016-12-08 10:46 被阅读71次

    共同点:

    • 都不能包含重复元素,用 equals 方法判断
    • 都是线程不安全的
    • Fail-fast behavior

    基本区别:

    • 迭代顺序:

      • HashSet :遍历时没有特定的顺序,从前到后遍历链表散列(数组 + 链表)
      • LinkedHashSet :遍历时按照插入的顺序或者访问的顺序。
      • TreeSet :遍历时按照元素升序(通过元素的 compareTo 方法进行比较)。
    • put/remove/get 时间复杂度

      • HashSet :O(1)
      • LinkedHashSet :O(1)
      • TreeSet :O(lgN)
    • 是否允许空的元素

      • HashSet :允许空的元素,因为 HashSet 基于 HashMap 实现,HashMap 允许空的 key
      • LinkedHashSet :允许空的元素,因为 LinkedHashSet 基于 LinkedHashMap 实现,LinkedHashMap 允许空的 key
      • TreeSet :元素不能为空,因为 TreeSet 基于 TreeMap 实现,HashMap 不允许空的 key,否则会产生运行时异常。
    • 实现方式

      • HashSet :基于 HashMap
      • LinkedHashSet :基于 LinkedHashMap
      • TreeSet :基于 TreeMap

    HashSet 的实现原理

    构造

    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable
    {
        static final long serialVersionUID = -5024744406713321676L;
    
        private transient HashMap<E,Object> map;
    
        // Dummy value to associate with an Object in the backing Map
        private static final Object PRESENT = new Object();
    
        /**
         * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
         * default initial capacity (16) and load factor (0.75).
         */
        public HashSet() {
            map = new HashMap<>();
        }
    

    可以看出,对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素。
    因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,我们应该为保存到 HashSet 中的对象覆盖 hashCode() 和 equals()。

    添加元素

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

    要添加的元素 e 作为 key,构造一个键值对 <e, PRESENT>,然后调用 HashMap 的 put 方法。(PRESENT 为一个对象,在上面的构造方法中可以看出)
    如果此 set 中尚未包含指定元素,则添加指定元素。更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2)) 的元素 e2,则向此 set 添加指定的元素 e。如果此 set 已包含该元素,则该调用不更改 set 并返回 false。但底层实际将将该元素作为 key 放入 HashMap。

    LinkedHashSet 的实现原理

    构造

    public class LinkedHashSet<E>
        extends HashSet<E>
        implements Set<E>, Cloneable, java.io.Serializable {
    
        private static final long serialVersionUID = -2851667679971038690L;
    
        /**
         * Constructs a new, empty linked hash set with the specified initial
         * capacity and load factor.
         *
         * @param      initialCapacity the initial capacity of the linked hash set
         * @param      loadFactor      the load factor of the linked hash set
         * @throws     IllegalArgumentException  if the initial capacity is less
         *               than zero, or if the load factor is nonpositive
         */
        public LinkedHashSet(int initialCapacity, float loadFactor) {
            super(initialCapacity, loadFactor, true);
        }
    

    可以看出:

    • LinkedHashMap 继承了 HashMap
    • LinkedHashSet 继承了 HashSet,实际上是创建了一个 LinkedHashMap:
      在 LinkedHashSet 构造方法中调用了父类 HashSet 的构造方法super(initialCapacity, loadFactor, true);
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    

    因此 LinkedHashSet 的实现原理可以参考 LinkedHashMap的实现原理

    TreeSet 的实现原理

    构造

    可以看出 TreeSet 在构造方法中实际上创建了一个 TreeMap。

    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;
        }
    
        /**
         * Constructs a new, empty tree set, sorted according to the
         * natural ordering of its elements.  All elements inserted into
         * the set must implement the {@link Comparable} interface.
         * Furthermore, all such elements must be <i>mutually
         * comparable</i>: {@code e1.compareTo(e2)} must not throw a
         * {@code ClassCastException} for any elements {@code e1} and
         * {@code e2} in the set.  If the user attempts to add an element
         * to the set that violates this constraint (for example, the user
         * attempts to add a string element to a set whose elements are
         * integers), the {@code add} call will throw a
         * {@code ClassCastException}.
         */
        public TreeSet() {
            this(new TreeMap<E,Object>());
        }
    

    引用:
    HashSet 的实现原理
    LinkedHashSet 的实现原理

    相关文章

      网友评论

        本文标题:Java 集合 HashSet VS LinkedHashSet

        本文链接:https://www.haomeiwen.com/subject/rjtjmttx.html