KeySet
我们在遍历HashMap
的时候会用到keySet()
获取到当前HashMap
的key值的一个Set
集合
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
可以看到直接创建了一个KeySet
对象,final class KeySet extends AbstractSet<K>
,KeySet
继承于AbstractSet
KeySet
有几个方法:
size
返回当前HashMap
的元素数量
clear
情况当前HashMap
的元素
iterator
返回一个KeyIterator
对象,用于遍历key值
contains
判断当前HashMap
中是否包含有指定的key值
remove
删除指定key值
forEach
遍历集合,每遍历一次返回一个key值
我们先来看iterator()
HashMap#KeySet#iterator():
public final Iterator<K> iterator() {
return new KeyIterator();
}
final class KeyIterator extends HashIterator implements Iterator<K> {
public final K next() { return nextNode().key; }
}
KeyIterator
继承于HashIterator
和Iterator
,只有一个next()
KeyIterator
KeyIterator
中的属性:
next
代表当前节点的下一个节点
current
代表当前节点
expectedModCount
代表修改次数 遍历期间不能对集合进行操作,否则expectedModeCount
不一致会抛出异常
index
当前节点的下标
keyIterator
中的方法
hasNext()
判断当前节点是否还有下一节点,即当前节点是否是尾节点
nextNode()
返回下一节点的node
值
remove()
删除当前节点
我们先来看构造器
HashMap#HashIterator#HashIterator():
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
构造器中对属性进行了初始化,并通过while循环,得到数组中的第一个不为空的元素下标以及值,并将此元素值赋给next
HashMap#HashIterator#hasNext():
public final boolean hasNext() {
return next != null;
}
hasNext()
判断当前元素是否有下个节点值,首次调用的话,next
为构造器中首次遍历到的值
HashMap#HashIterator#nextNode():
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
nextNode()
获取遍历到的当前节点,也可以理解为hasNext()
所判断的下一节点,主要是看最后一个判断,e
为当前要返回的节点,获取e
的下一节点,并赋值给next
,如果此时的next
为空,则说明当前链表已经遍历完毕,那么进入判断体,开始遍历下一个数组桶中的链表,并将此链表的头结点赋值给next
;
remove()
比较简单这里就不多说了。
说到这里我们结合KeySet
整体总结一遍流程:
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("w","c");
hashMap.put("a","h");
hashMap.put("n","u");
hashMap.put("g","a");
hashMap.put("c","n");
Iterator<String> iterator = hashMap.keySet().iterator();
while (iterator.hasNext()){
Log.i("chuan", "onResume: " + iterator.next());
}
上面是通过KeySet
对集合进行的遍历
首先我们通过keySet()获取到一个Set
对象(虽然Set
内部也是通过HashMap
实现的,但是这里只是用到了HashMap
的存储功能,并没有用到迭代器,否则就陷入了先有鸡还是先有蛋的死循环中)
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
public final Iterator<K> iterator() { return new KeyIterator(); }
然后通过KeySet
中的iterator()
获取到Iterator
对象,
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
最后通过HashIterator
的hashNext()
和nextNode()
获取到下一节点
其实继承HashIterator
的还有两个类,分别是获取value
和node
的ValueIterator
和EntryIterator
,逻辑都一样,都是先获取到指定的节点node
,然后在分别获取key
,value
或是node
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
网友评论