我不理解Guava为什么会提供将键设为软/弱引用以及将值设为软/弱引用的方法。
我只是想知道创建具有非软/弱值的软键的意义何在?我的意思是,当软引用开始被收集时,我们无法通过其键再找到该条目,那么为什么希望值留在映射中呢?
有人能给出以下用例吗:
- 弱键/软值
- 弱键/普通值
- 软键/弱值
- 软键/普通值
谢谢。
编辑 我不确定我的问题是否足够明确,所以我想知道:
- 当键(弱引用/软引用)被收集时,值(非弱引用/软引用)会发生什么
- 当值(弱引用/软引用)被收集时,键会发生什么
- 带有缺失部分(键或值)的条目是否保留在缓存中?
- 是否存在任何用例,您希望这样的条目留在缓存中。
编辑: 正如在Kevin Bourillon的答案中讨论的那样,最后我想我明白了为什么使用软键没有意义。 原因如下:
static class KeyHolder {
final private String key;
public KeyHolder(String key) {
this.key = key;
}
public String getKey() {
return key;
}
@Override
public boolean equals(Object o) {
KeyHolder that = (KeyHolder)o;
boolean equality = this.getKey().equals(that.getKey());
return equality;
}
@Override
public int hashCode() {
return key != null ? key.hashCode() : 0;
}
@Override
public String toString() {
return "KeyHolder{" +
"key='" + key + '\'' +
'}';
}
}
public static void main(String[] args) {
System.out.println("TESTING WEAK KEYS");
testMap( new MapMaker().weakKeys().<KeyHolder,String>makeMap() );
System.out.println("\n\n");
System.out.println("TESTING SOFT KEYS");
testMap(new MapMaker().softKeys().<KeyHolder, String>makeMap());
System.out.println("\n\n");
System.out.println("TESTING SOFT REFERENCES");
KeyHolder key1 = new KeyHolder("toto");
KeyHolder key2 = new KeyHolder("toto");
SoftReference<KeyHolder> softRef1 = new SoftReference<KeyHolder>(key1);
SoftReference<KeyHolder> softRef2 = new SoftReference<KeyHolder>(key2);
System.out.println( "equals keys? " + key1.equals(key2) );
System.out.println( "equals ref? " + softRef1.equals(softRef2) );
}
private static void testMap(Map<KeyHolder,String> map) {
KeyHolder strongRefKey = new KeyHolder("toto");
KeyHolder noStrongRefKey = new KeyHolder("tata");
map.put(strongRefKey,"strongRef");
map.put(noStrongRefKey,"noStrongRefKey");
// we replace the strong reference by another key instance which is equals
// this could happen for exemple in case of serialization/deserialization of the key
noStrongRefKey = new KeyHolder("tata");
System.gc();
System.out.println( "strongRefKey = " + map.get(strongRefKey) );
System.out.println( "noStrongRefKey = " + map.get(noStrongRefKey) );
System.out.println( "keyset = " + map.keySet() );
}
该代码生成以下输出:TESTING WEAK KEYS
strongRefKey = strongRef
noStrongRefKey = null
keyset = [KeyHolder{key='toto'}]
TESTING SOFT KEYS
strongRefKey = strongRef
noStrongRefKey = null
keyset = [KeyHolder{key='tata'}, KeyHolder{key='toto'}]
TESTING SOFT REFERENCES
toto == toto -> true
equals keys? true
equals ref? false
正如您所看到的,使用(不建议使用的)软键映射,包含“tata”键的KeyHolder仍然存在于映射中。
但请注意,我仍然无法通过新创建的键“new KeyHolder(“tata”);
”找到我的条目。
这是因为我的键具有有意义的相等性,但它们周围的引用包装器并不相等,因为它们的相等方法在Guava中没有被覆盖!
在这种情况下,是的,softKeys没有任何意义,因为您绝对需要保留对该键的标识引用才能检索它。
softKeys
看起来能够工作的情况下,weakKeys
都能更好地发挥作用。一旦键不再强烈可达,weakKeys
就允许它被GC回收。softKeys
可能会将其保留任意长时间--但是为了什么目的呢?因为如前所述,该键不再强烈可达,所以没有人可以查找该条目!因此,我们只剩下像“哦,但是我所有其他对该键的引用肯定也是软引用”,或者“哦,但是我有时会遍历asMap()条目并为某些原因恢复某些键”这样的边缘情况...这些情况实际上从未出现过。 - Kevin Bourrillion