HashSet LinkedHashSet TreeSet 源码浅析

Set 是一种去重的数据结构,经常可以使用到,而HashSet,LinkedHashSet, TreeSet是最常见的Set实现。

类图如下:

image.png

Set在Collection的基础上没有增加额外的方法,但是增加一些约束,一方面,元素不能重复,另一方面,添加的元素类型,有的不能为null,不能包含自己,添加不符合的元素的操作会抛出异常。

AbstractSet 只实现了equals, hashcode 和removeAll(); 因为AbstactCollection已经实现了一部分方法。

   public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Set))
            return false;
        Collection c = (Collection) o;
        if (c.size() != size())
            return false;
        try {
            return containsAll(c);
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    }

    public int hashCode() {
        int h = 0;
        Iterator i = iterator();
        while (i.hasNext()) {
            E obj = i.next();
            if (obj != null)
                h += obj.hashCode();
        }
        return h;
    }

hashCode是把每个元素的Hashcode累加,equals要求元素数量相同,并且包含对方的所有元素。

HashSet

在查看HashMap的时候,可以知道HashMap的Key已经Set,并且底层是hash表,因此是不是可以把Key取出来直接就变成HashMap了, 但是HashMap的Key是在Entry里,不可以单独创建,因此要创建一个HashMap 才可以使用Key。因此HashSet的实现,就是委托HashMap来实现的,由于不适用Map的Value,Map的所有value都指向同一个预定义好的对象,节约空间。

public class HashSet
    extends AbstractSet
    implements Set, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap 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 HashMap instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }
    ...
 }

LinkedHashSet

和 HashSet类似,仅仅是把HashMap替换成LinkedHashMap。之前我们知道LinkedHashMap有两种顺序,即添加顺序和访问顺序,但是LinkedHashSet的构造函数中无法选择,所以使用的是添加顺序。

HashSet 和LinkedHashSet都允许添加null为元素。

TreeSet

最后看一下,TreeSet 补充一下类图,


image.png

TreeSet 使得用迭代器访问时,可以以指定顺序排列,顺序按照comparetor或者 Comparable。 在TreeMap中,三个视角中,其中KeySet返回的就是NavigableSet,即TreeMap.KeySet 已经实现了NavigableSet。 而这个Set的实现,采用的是委托给NavigableMap。

而KeySet 是已经包权限静态类,而且是final的,不可以继承,因此TreeSet可以采取委托KeySet,再手动构造一个TreeMap,再创建KeySet

TreeSet() {
   NavigableMap map = new TreeMap();
   NavigableSet set = new TreeMap.KeySet(map);
}

实际上,这两委托两层,不如直接模仿KeySet的写法,再写一遍,直接委托即可。

    public TreeSet() {
        this(new TreeMap());
    }

所有的Value都设置成固定对象。

小节:

  1. HashSet,LinkedHash TreeSet 都是基于Map的三个对应实现的委托实现,只是用map的key,而不是用Map的Value。

END

你可能感兴趣的:(HashSet LinkedHashSet TreeSet 源码浅析)