当我阅读JDK的源代码时,我发现了一些让我很困惑的事情。 这就是HashMap如何跟踪entrySet或值。
这是HashMap的clear()代码
public void clear() {
Node<K,V>[] tab;
modCount++;
if ((tab = table) != null && size > 0) {
size = 0;
for (int i = 0; i < tab.length; ++i)
tab[i] = null;
}
}
}
我不知道这个方法如何控制entrySet。 据我所知,entrySet是由HashMap的实例缓存的,但我从来没有发现它发生任何变化。
那里的代码只有清楚的表格。 这是HashMap的一些字段。
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
transient Node<K, V>[] table;
transient Set<Map.Entry<K, V>> entrySet;
transient size;
transient int modCount;
int threshold;
final float loadFactor;
// other part
}
我在这里不明白。由于clear方法只更改表,因此它如何影响entrySet。
我使用JUnit来测试我的想法。在调用clear()方法后,HashMap的entrySet为空。
这是下面的entrySet()代码
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
如果entrySet不为null,则返回高速缓存的entrySet,但clear()方法永远不会更改高速缓存的entrySet。它是如何工作的?
答案 0 :(得分:2)
entrySet()
只是一种观点。除了(隐含地)对HashMap
的引用之外,其中没有任何内容。它不会创建第二个数据结构,Set
方法只是直接访问地图。
请参阅私有HashMap.EntrySet
类以了解其实现方式。它是一个内部类,因此它可以看到封闭的HashMap
实例(“拥有”它的对象)。
这是一个非常简单的例子,其工作方式完全相同:
interface Foo {
void setFizz(int fizz);
int getFizz();
}
interface Bar {
void setBazz(int bazz);
int getBazz();
// returns a view of this Bar as if it were a Foo
Foo asFoo();
}
class BarImpl implements Bar {
int bazz;
@Override
public int setBazz(int bazz) {
this.bazz = bazz;
}
@Override
public int getBazz() {
return this.bazz;
}
@Override
public Foo asFoo() {
return new Foo() {
@Override
public int setFizz(int fizz) {
BarImpl.this.bazz = fizz;
}
@Override
public int getFizz() {
return BarImpl.this.bazz;
}
};
}
}
只有一个int
,调用asFoo()
只是让我们访问Bar
,就像它是Foo
一样。