本文共 2281 字,大约阅读时间需要 7 分钟。
Set不保存重复的元素。Set中最常被使用的是测试归属性,你可以很容易的询问某个对象是否在某个Set中。Set具有与Collection完全一样的接口,因此没有任何额外的功能。实际上Set就是Collection,只是行为不同。
Set接口内容如下图:
从上图中我们可以很清晰的看出,Set接口继承了Collection接口,甚至可以说Set接口就是Collection接口。Set|------HashSet| |-------LinkedHashSet|------TreeSet
HashSet是基于HashMap来实现的,操作很简单,更像是对HashMap做了一次“封装”,而且只使用了HashMap的key来实现各种特性。
// HashSet内部包含了一个HashMap private transient HashMapmap; // 定义一个虚拟的Object。 // PRESENT是向map中插入key-value对应的value // 向map中添加键值对时,键值对的值固定是PRESENT private static final Object PRESENT = new Object();
HashSet提供如下四种初始化方法:
public HashSet() { map = new HashMap<>(); } public HashSet(Collection c) { 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的初始化过程可以看作是内部HashMap的初始化过程,不再赘述。
正如前言中所述,Set不保存重复的元素,Set中最常被使用的是测试归属性。Set中最频繁被调用的方法就是add、remove、contains三个方法。
public boolean add(E e) { return map.put(e, PRESENT)==null; }
add方法的实现逻辑就是往内部成员map中添加e和PRESENT组成的键值对,根据返回值是否为null判断是否添加成功。HashMap中如果内部已经存在key为e的键值对,则返回对应的value,否则返回null。此处可以看到,HashSet内部的map中所有键值对的value都是PRESENT。
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
remove方法调用HashMap的remove方法,根据返回值判断是否删除成功。
public boolean contains(Object o) { return map.containsKey(o); }
contains方法通过调用HashMap的containsKey方法判断是否包含相关对象。
LinkedHashSet继承自HashSet,源码更少、更简单,唯一的区别是LinkedHashSet内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的。
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 c) { super(Math.max(2*c.size(), 11), .75f, true); addAll(c); }
LinkedHashSet通过调用HashSet包私有的构造方法来初始化,使用LinkedHashMap代替HashMap作为对象的存储载体。
本文主要讲述了Set接口及其部分实现类的内部逻辑,Set接口的更多高级实现,例如TreeSet后续还会有讲述,希望能对读者有所帮助。