我正在编写一个简单的基于 HashMap
的缓存,其工作方式如下:
- 如果请求的
键
在缓存中,返回它的值
。 - 如果请求的
key
不,运行一个方法根据key
生成value
,存储两者都返回值
。
代码:
import java.util.HashMap;
abstract class Cache<K, V> extends HashMap<K, V> {
@Override
public V get(Object key) {
if (containsKey(key)) {
return super.get(key);
} else {
V val = getData(key);
put((K)key, val); // this is the line I'm discussing below
return val;
}
}
public abstract V getData(Object key);
}
它非常简单并且运行良好。但是,我讨厌 Sun 决定get()
将Object
作为参数而不是K
。我已经阅读了足够多的内容,知道它背后有一些基本原理(我不同意,但那是另一个故事)。
我的问题出在注释行中,因为看起来 Actor 必须 未选中。由于类型删除,我无法检查 key
是否属于 K
类型(这是正确的 put()
功能所必需的)和因此,该方法很容易出错。
一个解决方案是从“是一个”切换到“有一个”HashMap
关系,这样更好更干净,但是 Cache
无法实现 Map
这会很好,原因有几个。代码:
import java.util.HashMap;
import java.util.Map;
abstract class Cache<K, V> {
private final Map<K, V> map = new HashMap<K, V>();
public V get(K key) {
if (map.containsKey(key)) {
return map.get(key);
} else {
V val = getData(key);
map.put(key, val);
return val;
}
}
public abstract V getData(K key);
}
任何人都可以想出任何其他(甚至是 hackish)解决方案,以便我可以将 Cache
维护为 Map
并且仍然是类型安全的 get(Object key)
和 put(K key, V val)
?
我唯一能想到的是创建另一个名为 getValue(Key k)
的方法,它将委托(delegate)给 get(Object key)
,但我可以'强制任何人使用新方法而不是通常的方法。
最佳答案
没有。您已经找到了切换到“拥有”关系的正确解决方案。 (坦率地说,让 get
方法计算一个新值(如果一个值尚不存在)是令人惊讶的,这违反了 Map
契约,并且可能导致许多其他方法出现极其奇怪的行为。这是为什么 Guava 离开了 MapMaker
,它提供了几乎完全相同的行为——因为它是如此 riddled 有问题。)
就是说,例如 Guava 的Cache
是它暴露了一个 Map<K, V> asMap()
查看,这是您可以做的事情。这为您提供了 Map
的大部分优势不影响类型安全。
关于Java - 扩展 HashMap - 对象与泛型行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10354103/