我不习惯处理 Java 中的软引用和弱引用,但我理解这个原理,因为我习惯于处理像 Gemfire 这样的数据网格,当内存已满时,它会为 hdd 功能提供溢出,可能使用软引用或类似的东西猜测。
我在番石榴中不明白的是,它提供了使键变软/弱的方法,以及使值变软/弱的方法。
我只是想知道创建具有非软值的软键有什么意义?我的意思是,当开始收集软引用时,我们无法再通过它的键找到条目,那么为什么我们希望这些值保留在映射中呢?
有人可以给我们一些用例:
- 弱键/软值
- 弱键/正常值
- 软键/弱值
- 软键/正常值
谢谢
编辑 我不确定我的问题是否足够精确,所以我想知道的是:
- 收集密钥时(弱/软),值会发生什么(非弱/软)
- 当一个值被收集(弱/软)时,键会发生什么
- 缺少部分(键或值)的条目是否保留在缓存中?
- 当您希望此类条目保留在缓存中时,是否有任何用例。
编辑: 正如 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 没有任何意义,因为您绝对需要保留对该密钥的身份引用才能检索它。