WeakHashMap 的 keySet 条目永远不会为空吗?
如果我迭代 WeakHashMap 的键集,是否需要检查 null 值?
WeakHashMap<MyObject, WeakReference<MyObject>> hm
= new WeakHashMap<MyObject, WeakReference<MyObject>>();
for ( MyObject item : hm.keySet() ) {
if ( item != null ) { // <- Is this test necessary?
// Do something...
}
}
换句话说,当我迭代 WeakHashMap 的元素时,它们可以被收集吗?
编辑
对于这个问题,我们可以假设哈希映射中没有添加null
条目。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我不熟悉
WeakHashMap
,但您可能有一个 null 对象。看这个例子:I'm not familiar with
WeakHashMap
, but you might have one null object. see this example:再次来自 WeakHashMap javadoc:
我读为:是的...当 WeakHaskMap 中没有对某个键的剩余外部引用时,那么该键可能会被GC,从而使关联的值无法访问,因此它(假设有)没有外部直接引用)适合 GC。
我将测试这个理论。这只是我对 doco 的解释...我没有任何 WeakHashMap 的经验...但我立即看到它作为“内存安全”对象缓存的潜力。
干杯。基思.
编辑:探索WeakHashMap...专门测试我的理论,即对特定键的外部引用将导致该键被保留...这是纯粹的废话;-)
我的测试工具:
一次测试运行的(相当令人困惑,我认为)结果:
当我的代码正在执行时,按键似乎仍然消失......在 GC 提示后可能需要微睡眠。 . 给 GC 时间来做它的事情。无论如何,这种“波动”是有趣的行为。
编辑2:是的,直接在
System.gc()之后添加行
使结果“更可预测”。try{Thread.sleep(10);}catch(Exception e){}
;嗯...当 GC 启动时,缓存就会完全消失...在真实应用程序中的任意时间...没有多大用处...嗯...我想知道 WeakHashMap 的用途是什么? ;-)
最后编辑,我保证
这是我的krc/utilz/Random(在上面的测试中使用)
Again from WeakHashMap javadoc:
Which I read as: Yep... When there are no remaining external references to a Key in WeakHaskMap, then that Key maybe GC'd, making the associated Value unreachable, so it to (presuming there are no external references directly to it) is elligible for GC.
I'm going to test this theory. It's only my interpretation of the doco... I don't have any experience with WeakHashMap... but I immediately see it's potential as "memory-safe" object-cache.
Cheers. Keith.
EDIT: Exploring WeakHashMap... specifically testing my theory that an external-references to the particular key would cause that key to be retained... which is pure bunkum ;-)
My test harness:
The (rathering perplexing, I think) results of one test-run:
It would appear that keys are still disappearing WHILE my code is executing... possibly a micro-sleep is required after the GC-hint... to give the GC time to do it's stuff. Anyway, this "volatility" is interesting behaviour.
EDIT 2: Yup, adding the line
try{Thread.sleep(10);}catch(Exception e){}
directly after theSystem.gc();
makes the results "more predictable".Hmmm... A cache that just completely disappears when the GC kicks in... at arbitrary times in a real app... not much use... Hmmm... What is WeakHashMap for I wonder? ;-)
Last EDIT, I promise
Here's my krc/utilz/Random (used in the above test)
假设您没有将
null
键值插入到WeakHashMap
中,则您不需要需要检查迭代的键值是否为迭代键集时null
。在迭代条目集时,您也不需要需要检查在迭代的Map.Entry
实例上调用的 getKey() 是否为null
。两者都由文档保证,但有点间接;它是 Iterator.hasNext 的合同() 提供这些保证。WeakHashMap 的 JavaDoc< /a> 状态:
Iterator.hasNext() 的 JavaDoc 指出:
因为键集和条目集视图满足
Set
约定(根据Set
的要求) code>Map 合约其中WeakHashMap
实现),由 Set.iterator() 方法必须满足Iterator
契约。当 hasNext() 返回
true
时,Iterator
合约要求对Iterator
实例上的 next() 的下一次调用必须返回有效值。WeakHashMap
满足Iterator
契约的唯一方法是让 hasNext() 实现在返回true
,从而防止垃圾收集器清除对WeakHashMap
所持有的键值的弱引用,从而防止该条目自动从WeakHashMap< 中删除/code> 这样 next()有返回值。
事实上,如果您查看
WeakHashMap
的源代码,您会发现HashIterator
内部类(由键、值和条目迭代器实现使用)具有一个currentKey
字段保存对当前键值的强引用,nextKey
字段保存对下一个键值的强引用。currentKey
字段允许HashIterator
实现 Iterator.remove() 完全符合该方法的约定。nextKey
字段允许HashIterator
满足 hasNext() 的约定。话虽这么说,假设您想通过调用 toArray() 来收集映射中的所有键值,然后迭代此键值快照。有几种情况需要考虑:
如果调用返回
Object[]
的无参数 toArray() 方法或传入零长度数组,如下所示:.. 那么您不需要需要检查
item
是否为null
,因为在这两种情况下,返回的数组都将被修剪以保存迭代器返回的元素的确切数量。如果您传入一个长度 >=
WeakHashMap
的当前大小的数组,如下所示:.. 那么
null
检查是必要的。原因是,在 size() 返回一个值(用于创建存储键的数组)和 toArray() 完成对 WeakHashMap 的键的迭代之间的时间里,条目可能已被自动删除。这是 Collection.toArray() 的 JavaDoc:<块引用>
如果此集合适合指定数组且有剩余空间(即,该数组的元素多于此集合),则数组中紧随集合末尾的元素将设置为
null
。 (仅当调用者知道此集合不包含任何null
元素时,这才有助于确定此集合的长度。)因为您知道您尚未将
null
键值插入到WeakHashMap
中,所以您可以在看到第一个null
值时中断(如果您看到null
)。与前一种情况略有不同,如果您传入一个非零长度的数组,那么您需要
null
检查,因为“有空闲空间”情况可能在运行时发生。Assuming that you don't insert a
null
key value into aWeakHashMap
, you do not need to check whether the key value of the iteration isnull
when iterating through the key set. You also do not need to check whether getKey() called on theMap.Entry
instance of the iteration isnull
when iterating through the entry set. Both are guaranteed by the documentation, but it's somewhat indirect; it is the contract of Iterator.hasNext() that provides these guarantees.The JavaDoc for
WeakHashMap
states:The JavaDoc for Iterator.hasNext() states:
Because the key set and entry set views satisfy the
Set
contract (as required by theMap
contract whichWeakHashMap
implements), the iterators returned by the Set.iterator() method must satisfy theIterator
contract.When hasNext() returns
true
, theIterator
contract requires that the next call to next() on theIterator
instance must return a valid value. The only way forWeakHashMap
to satisfy theIterator
contract is for the hasNext() implementation to keep a strong reference to the next key when it returnstrue
, thereby preventing the weak reference to the key value held by theWeakHashMap
from being cleared by the garbage collector, and, as a consequence, preventing the entry from being automatically removed from theWeakHashMap
so that next() has a value to return.Indeed, if you look at the source of
WeakHashMap
, you will see that theHashIterator
inner class (used by the key, value, and entry iterator implementations) has acurrentKey
field that holds a strong reference to the current key value and anextKey
field that holds a strong reference to the next key value. ThecurrentKey
field allowsHashIterator
to implement Iterator.remove() in full compliance with that method's contract. ThenextKey
field allowsHashIterator
to satisfy the contract of hasNext().That being said, suppose you want to gather up all key values in the map by calling toArray(), and then iterate through this snapshot of key values. There are a few cases to consider:
If you call the no-argument toArray() method that returns
Object[]
or pass in a zero-length array, as in:.. then you do not need to check whether
item
isnull
because in both cases, the array returned will be trimmed to hold the exact number of elements that were returned by the iterator.If you pass in an array of length >= the
WeakHashMap
's then-current size, as in:.. then the
null
check is necessary. The reason is that, in the time between when size() returned a value (which is used to create the array to store the keys) and toArray() finishes iterating through the keys of theWeakHashMap
, an entry may have been automatically removed. This is the "room to spare" case mentioned in the JavaDoc for Collection.toArray():Because you know that you have not inserted a
null
key value into theWeakHashMap
, you can break upon seeing the firstnull
value (if you see anull
).A slight variant of the previous case, if you pass in an array of non-zero length, then you need the
null
check for the reason that the "room to spare" case might happen at runtime.WeakHashMap 允许 null 作为键和值。您可以添加空键和值。 因此,如果您没有插入空条目,则不需要添加空检查
WeakHashMap permits null as key and value. You can add null key and value. So in case, if you have not inserted null entries, then you don't need to add the null check
来自 WeakHashMap< /a> 文档中,放入哈希映射的键是模板化类型,这意味着它是从 java.lang.object 继承的。结果,它可能为空。因此,某个键可能为空。
From the WeakHashMap documentation, the key that is placed into the hash map is of a templated type, which means it is inherited from java.lang.object. As a result, it may be null. So, a key may be null.