java set集合解析
set
这里我们首先看到set接口
public interface Set<E> extends Collection<E>
注意一下官方对其的描述
* A collection that contains no duplicate elements. More formally, sets
* contain no pair of elements <code>e1</code> and <code>e2</code> such that
* <code>e1.equals(e2)</code>, and at most one null element. As implied by
* its name, this interface models the mathematical <i>set</i> abstraction.
*
大致意思是Set是一个不能含有重复元素的collection,更准确的说其不能有重复元素,同时最多只能有一个空的元素。
下面是对set及其衍生类的介绍
* @param <E> the type of elements maintained by this set//由该set维护的元素
*
* @author Josh Bloch
* @author Neal Gafter //作者
* @see Collection //继承于collection
* @see List //衍生类
* @see SortedSet //排序的set接口
* @see HashSet //由hash值确定的set
* @see TreeSet //依据treeMap生成生成
* @see AbstractSet //一个通用的set模板
* @see Collections#singleton(java.lang.Object)
* @see Collections#EMPTY_SET
* @since 1.2
Collection
我们接着看其继承的Collection的文档
public interface Collection<E> extends Iterable<E>
.The root interface in the <i>collection hierarchy</i>. A collection
* represents a group of objects, known as its <i>elements</i>. Some
* collections allow duplicate elements and others do not. Some are ordered
* and others unordered. The JDK does not provide any <i>direct</i>
* implementations of this interface: it provides implementations of more
* specific subinterfaces like <tt>Set</tt> and <tt>List</tt>. This interface
* is typically used to pass collections around and manipulate them where
* maximum generality is desired
大致的意思是这是集合层次的根接口,有些集合允许重复元素,而另一些则不允许。有些是有序的,有些是无序的。JDK没有直接提供任何接口的实现:它提供了更多的特定的子接口,如Set和List。这个接口通常用于传递集合并对其进行操作,最大通用性。
其实就是一个集合的根接口,这里通过封装一些方法,实现自己的方法,特性,同时也为后面的集合提供方便。
Iterable
可以看到这个接口同样继承于一个接口Iterable,原来还没有到底呀,我们接着看Iterable。
public interface Iterable<T>
这下终于到底了,接着我们看下官方对其的描述
* Implementing this interface allows an object to be the target of
* the "for-each loop" statement.
继承这个接口实现for-each方法,也就是我们的遍历的方法,都知道当我们需要进行遍历的时候,需要直接或者间接继承
Iterable,同时对里面的Iterator iterator()方法进行重写,这也是自己实现集合中的遍历的方法。
既然set的关系都理清了,我们接着看下他的具体实现的类
AbstractSet
看过源码的应该都知道,如果说set是最基础的接口,定义了set的基本函数的话,那么AbstractSet 就是一个骨架
官方文档的描述。
* This class provides a skeletal implementation of the <tt>Set</tt>
* interface to minimize the effort required to implement this
* interface. <p>
这个类提供了Set接口的框架实现,以最小化实现这个接口所需的工作量。也就是减轻工作量的效果。
这里列出里面实现的三个具体方法。
public boolean equals(Object o) { //equals方法
if (o == this) //如果对象相同
return true;
if (!(o instanceof Set)) //如果不是set对象
return false;
Collection c = (Collection) o; //强转为Collection,因为本身继承于AbstractCollection
if (c.size() != size()) //如果长度不一样
return false;
try {
return containsAll(c); //再次通过函数判断
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
public int hashCode() {
int h = 0;
Iterator<E> i = iterator(); //获取迭代器对象
while (i.hasNext()) { //遍历所有同时将所以元素的hashcode相加
E obj = i.next();
if (obj != null)
h += obj.hashCode();
}
return h;
}
`public boolean removeAll(Collection
HashSet
在上一篇中讲解了HashMap的实现,我们打开HashSet的源码
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
可以发现其继承于AbstractSet(一个set的骨架基类),同样的,其实现了set接口,Cloneable可复制接口,Serializable序列化接口。
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
可以发现HashSet的构造函数就是通过实例化一个value为Object的HashMap。
同样我们可以看到这里的iterator同样是使用了map中的keySet中的iterator
public Iterator<E> iterator() {
return map.keySet().iterator(); //通过调用HashMap的keySet返回迭代器
}
可以看到真正的实现了Iterator代码的复用,最终又是回到了Hashmap中的HashIterator中,同样实现了Iterator的操作
private abstract class HashIterator<E> implements Iterator<E> {//重写了Iterator
HashMapEntry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
HashMapEntry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
HashMapEntry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
HashMapEntry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
HashMapEntry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
这里的add操作可以看到是通过HashMap的put操作完成的,同时是将一个value为PRESENT也就是Object的类添加进去,也就达到了只存储key的效果
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
对于HashSet的遍历,因为上面返回了keyset,所以就不用多说了,相当于返回了一个只有key的set集合,可以直接进行迭代操作。