由于 HashSet,TreeSet 主要是利用了 HashMap 和 TreeMap,所以首先可以参考:
- Java 集合:HashMap(put方法的实现与哈希冲突)
- Java 集合:TreeMap 的使用(不包括原理,仅仅是简单的使用 demo)
HashSet
HashSet 实现了 Set 接口,而 Set 接口是继承于 Collection 接口,所以可以认为 Set 接口是 List 接口的兄弟。
对于 Set 接口,如注释所说:
* A collection that contains no duplicate elements. More formally, sets
* contain no pair of elements e1
and e2
such that
* e1.equals(e2)
, and at most one null element. As implied by
* its name, this interface models the mathematical set abstraction.
所以说不重复,而且HashSet 底层使用的是 HashMap,所以也无序。 这两点是和 List 接口下的 ArrayList,LinkedList 等的一大区别。
我们知道,HashMap 是键值对的形式,HashSet 没有什么键值对的概念,那它内部具体又是怎么利用 HashMap 实现的呢?
其实就是 HashSet 用了一个空对象,如 private static final Object PRESENT = new Object
- 用这个空对象来填充 HashMap 的 value 域
- 用这个空对象来填充 HashMap 的 value 域
- 用这个空对象来填充 HashMap 的 value 域
如下面的 add 方法:
private transient HashMap map;
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
所以从这里就可以看出:
- 利用了 HashMap 实现。HashSet 的方法就是调用 HashMap 的对应的方法。
- 用空对象来填充 HashMap 的 value 域
TreeSet
这里需要知道,平常我们所使用的 ArrayList,LinkedList 的元素是按照插入的时候的顺序排列的,而不是按照这个元素的大小之类的排序,假如我们需要有这个功能的话,那么 TreeSet 就派上用场了。
当创建一个 TreeSet 的时候:
private transient NavigableMap m;
public TreeSet() {
this(new TreeMap());
}
TreeSet(NavigableMap m) {
this.m = m;
}
可以看到,内部是使用了 TreeMap。
当 add(E e)
方法的时候:
private static final Object PRESENT = new Object();
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
也是和 HashSet 一样,令对应的 Map 的 value 域为一个随便不要的对象就行。
其他的方法如:
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
public void clear() {
m.clear();
}
等等都是类似的,这里不再累赘。