题外话:小编应老师要求要总结一下java知识,看了很多朋友写的博客,受益匪浅,自己也尝试写下对Set接口的分析
Set接口简单文字介绍:
一个不包含重复的无序的Collection,Set不包含两个相同的元素(使用equals方法比较返回为true),并且最多包含一个null元素,该结构是按照集合的数学定义来实现的,而且Set的特殊情况在于该集合不允许包含其自身作为元素。
【*:如果将可变对象作为Set集合的元素,那么必须极其小心,如果对象是Set中的某个元素,以一种影响equals比较的方式改变了对象的值的话,那么这种情况下Set集合的值会变得不确定。】
Set的方法列表和Collection是完全一样的,所以这里没有列出来,需要注意的是:在父接口所有的构造方法、add、equals以及hashCode等方法的协定上,Set接口还加入了其他规定,这些规定超出了从Collection接口继承的相关内容。Set集合的主要特点就是无序、不可重复,其实Set可能更容易理解,因为Set和集合的数学定义是一致的。如果元素重复即equals返回为true就不会被接受
一.源码原理理解
下面是Set接口中的特别方法
boolean add(E e);
boolean addAll(Collection<? extends E> c);
Set接口中添加元素不再用Map中的put了,而是使用add了,除此以外没什么特别的
下面我们顺着一条线分析,查看HashSet这个类对Set的实现,下面HashSet的成员变量
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
可以清楚的看到map这个成员,其实Set就是基于Map,借用了Map中的Key,value没有用上
下面是构造器
public HashSet() {
map = new HashMap<E,Object>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<E,Object>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<E,Object>(initialCapacity);
}
对于三个构造方法都是new了一个HashMap,不过参数不同,对于上面参数,熟悉Map的朋友不会陌生上面都是有关Map性能的,具体内容可参考HashMap相关知识
下面是添加删除等方法实现
public Iterator<E> iterator() {
return map.keySet().iterator();
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean contains(Object o) {
return map.containsKey(o);
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public void clear() {
map.clear();
}
所有的方法都是借用了HashMap的方法,HashSet几乎没有做任何事情。
总结:我们知道Map的性质,key不能重复,只能有一个null,Set恰恰利用的就是这种性质使得实现变的非常的容易