我正在编写一个基于HashMap
的简单缓存,其工作原理如下:
key
在缓存中,请返回其value
。key
不是,请运行根据value
生成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
。我已经阅读了足够的知识,知道它背后有一些理由(我不同意,但这是另一个故事)。
我的问题出现在注释行中,因为似乎未选中强制转换 。由于类型擦除,我无法检查key
是否为K
类型(正确的put()
功能所需),因此该方法容易出错。
一种解决方案是从“is a”切换到“has a”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)
方面仍然是类型安全的{1}}?
我唯一能想到的是制作另一个名为getValue(Key k)
的方法,该方法将委托给get(Object key)
,但是我不能强迫任何人使用新方法而不是通常的方法
答案 0 :(得分:15)
不。您已经找到了切换到“has-a”关系的正确解决方案。 (坦率地说,让get
方法计算一个新值(如果一个尚不存在)是令人惊讶的,违反了Map
契约,并且可能导致许多其他方法的极其奇怪的行为。很大一部分原因是为什么Guava离开MapMaker
,这几乎提供了这种确切的行为 - 因为它只是riddled有问题。)
那说,例如番石榴的Cache
确实暴露了Map<K, V> asMap()
视图,这是你可以做的事情。这样可以在不影响类型安全的情况下为Map
提供大部分优势。
答案 1 :(得分:0)
明确地说,has-a关系是正确的实现。应该从缓存类中删除生成值的业务逻辑。