HashSet在我们编程中是最长使用的一种Set,它能够以常数时间插入/删除/查找。正因为其强大的性能,python里的set也是以它的原理为实现的。我们都知道python向来崇尚“简单好于复杂 ————python之禅”,连python都认可的数据结构当然要看看。
经过多场面试,可能面试经验总是说:HashSet是以HashMap来实现的。那么,具体是怎样实现的呢?
接下来就探索一下它的底层原理——我说它才200多行你敢信?
首先,观察它的字段:
static final long serialVersionUID = -5024744406713321676L;//序列化时校验ID
private transient HashMap<E,Object> map;//HashMap结构
private static final Object PRESENT = new Object();//一个占位对象。
聪明的小伙伴已经猜到了——HashMap的key-value中的value都将以PRESENT代替,这样不占用空间,并且操作方便。
构造器:
public HashSet() {
map = new HashMap<>();//默认构造一个HashMap
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);//调用HashMap,并且集合的元素保持3/4的装填率
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);//自定义
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
//由dummy参数表示是否构造有序hashset
}
几个操作方法:
public boolean contains(Object o) {
return map.containsKey(o);//搜索
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;//插入(以PRESENT占位)
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;//删除
}
通过查看这几个方法,我们可以得出几个设计哲学的发现:
1、因为所有的键值对的值都引用的是一个占位对象,所以使用了“单例模式”。
2、HashSet的方法远远不如HashMap的丰富,所以使用了“代理模式”,通过调用HashMap的方法达到目的,因为很多方法被隐藏了起来,我们称这种方法为接口窄化。
那么分析到此结束。