与hashmap类似,字面上看,hashset由两个单词组成:hash和set。其中,set表示接口,实现set接口也有多种方式,各有特点,hashset实现的方式利用了hash。下面,我们先看set接口,然后看实现原理,最后总结分析hashset的特点。
目录
set
set表示的是没有重复元素、且不保证顺序的容器接口,它扩展了collection,但没有定义任何新的方法,不过,对于其中的一些方法,它有自己的规范。set接口的定义如下:
public interface set<e> extends collection<e> {
int size();
boolean isempty();
boolean contains(object o);
// ... (其他方法)
iterator<e> iterator();
object[] toarray();
<t> t[] toarray(t[] a);
boolean add(e e);
boolean remove(object o);
boolean containsall(collection<?> c);
boolean addall(collection<? extends e> c);
boolean retainall(collection<?> c);
boolean removeall(collection<?> c);
void clear();
boolean equals(object o);
int hashcode();
}
与hashmap类似,hashset的构造方法有:
public hashset()
public hashset(int initialcapacity)
public hashset(int initialcapacity, float loadfactor)
public hashset(collection<? extends e> c)
其中initialcapacity和loadfactor的含义与hashmap中的是一样的。与hashmap类似,hashset要求元素重写hashcode和equals方法,且对于两个对象,如果equals相同,则hashcode也必须相同,如果元素是自定义的类,需要注意这一点。
实现原理
hashset内部是用hashmap实现的,它内部有一个hashmap实例变量,如下所示:
private transient hashmap<e,object> map;
我们知道,map有键和值,hashset相当于只有键,值都是相同的固定值,这个值的定义为:
private static final object present = new object();
理解了这个内部组成,它的实现方法也就比较容易理解了,我们来看下hashset的构造方法,主要就是调用了对应的hashmap的构造方法:
public hashset(int initialcapacity, float loadfactor) {
map = new hashmap<>(initialcapacity, loadfactor);
}
接受collection参数的构造方法稍微不一样,代码为:
public hashset(collection<? extends e> c) {
map = new hashmap<>(math.max((int) (c.size()/.75f) + 1, 16));
addall(c);
}
c.size()1.75f用于计算initialcapacity,0.75f是loadfactor的默认值。
add方法的代码:
public boolean add(e e) {
return map.put(e, present)==null;
}
调用了map的put方法,元素e用于键,值就是固定值present,put返回null表示原来没有对应的键,添加成功了。hashmap中一个键只会保存一份,所以重复添加hashmap不会变化。
检查是否包含元素,就是检查map中是否包含对应的键。代码为:
public boolean contains(object o) {
return map.containskey(o);
}
删除元素就是调用map的remove方法,返回值为present表示原来有对应的键且删除成功了。代码为:
public boolean remove(object o) {
return map.remove(o)==present;
}
迭代器就是返回map的keyset的迭代器,代码为:
public iterator<e> iterator() {
return map.keyset().iterator();
}
特点和应用
hashset有如下特点:
1)没有重复元素;
2)可以高效地添加、删除元素、判断元素是否存在,效率都为o(1);
3)没有顺序。
hashset有很多应用场景,比如:
1)去重,如果对去重后的元素没有顺序要求,则hashset可以方便地用于去重;
2)保存特殊值,set可以用于保存各种特殊值,程序处理用户请求或数据记录时,根据是否为特殊值判断是否进行特殊处理,比如保存ip地址的黑名单或白名单;
3)集合运算,使用set可以方便地进行数学集合中的运算,如交集、并集等运算,这些运算有一些很现实的意义。比如,用户标签计算,每个用户都有一些标签,两个用户的标签交集就表示他们的共同特征,交集大小除以并集大小可以表示他们的相似程度。
发表评论