我正尝试使用Java7的WeakHashMap,但发现它的isEmpty()方法给我错误的结果。
import java.util.Map;
import java.util.WeakHashMap;
public class Test
{
public static void main(final String[] args)
{
final Map<String, Boolean> map = new WeakHashMap<>();
String b = new String("B");
map.put(b, true);
b = null;
System.gc();
System.out.println(map.isEmpty());
System.out.println(map.keySet().isEmpty());
System.out.println(map);
}
}
实际结果:
false
true
{}
也就是说
map.isEmpty()和map.keySet()。isEmpty()不一致。 有人可以帮我理解吗?非常感谢。
答案 0 :(得分:7)
您应该阅读WeakHashMap
的Javadoc:
WeakHashMap
类的行为部分取决于垃圾回收器的动作,因此,一些熟悉的(尽管不是必需的)Map
不变量对此类不成立。因为垃圾回收器可以随时丢弃键,所以WeakHashMap
的行为就像是未知线程正在静默删除条目。特别是,即使您在WeakHashMap
实例上进行同步并且不调用其任何mutator方法,对于size
,isEmpty
方法也有可能随着时间的推移返回较小的值。 }方法返回false
,然后返回true
,对于containsKey
方法返回给定密钥的true
,然后返回false
,对于get
方法返回给定键的值,但随后返回null
,put
方法返回null
,而remove
方法返回{{ 1}},用于以前似乎在地图中的某个键,并对该键集,值集合和条目集进行连续检查,以得出依次减少的元素数量。
您所看到的效果的全部不足之处是完全有效的。
答案 1 :(得分:2)
...此结果是快照,可能无法反映未处理的条目 在下次尝试访问之前将被删除,因为它们不是 已被引用。
因此,您希望isEmpty()
在GC 后和访问后之后返回正确的值。这段代码演示了这一点:
public class Scratch1 {
public static void main(final String[] args) {
final Map<String, Boolean> map = new WeakHashMap<>();
String b = new String("B");
map.put(b, true);
b = null;
System.gc();
// map not internally accessed at this point
System.out.println(map.isEmpty());
// let's access the Map's internals (and hopefully coerce
// it into removing no-longer-referenced keys)
System.out.println(map.keySet()
.isEmpty());
// map HAS now been accessed
System.out.println(map.isEmpty());
}
}
收益:
false
true
true