我正在写一个基于 HashMap
的缓存,它的工作方式如下:
- 如果请求的
key
在缓存中,则返回其对应的value
。 - 如果请求的
key
不在缓存中,则运行一个根据key
生成value
的方法,将键值对存储起来,并返回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)
的类型安全方面保持不变?
我唯一想到的办法是创建另一个方法,比如 getValue(Key k)
,并将其委托给 get(Object key)
,但是我不能强制任何人使用新的方法而不是通常用的那个。
getA
或myget
,但是你不能改变 Map.get() 的行为,因为你无法强制使用接口而不是直接使用你的类的代码重新编译。 - Peter Lawrey