Java - 扩展HashMap - 对象与泛型行为

Pet*_*ček 15 java generics inheritance casting

我正在编写一个HashMap基于简单的Cache,其工作方式如下:

  1. 如果请求key 在缓存中,返回它value.
  2. 如果请求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);
}
Run Code Online (Sandbox Code Playgroud)

这很简单,效果很好.但是,我讨厌太阳的决策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);
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以提出任何其他(甚至是hackish)解决方案,以便我可以保持Cache成为一个Map并且仍然是类型安全的get(Object key)put(K key, V val)

我能想到的唯一的事情就是让命名即另一种方法getValue(Key k),将委托给get(Object key),但我不能强迫任何人使用新的方法,而不是往常的.

Lou*_*man 15

不.您已经找到了切换到"has-a"关系的正确解决方案.(坦率地说,get如果一个尚未存在的方法计算一个新值是令人惊讶的,违反了Map合同,并且可能导致许多其他方法的极其奇怪的行为.这是Guava离开的原因的一个重要部分MapMaker,它几乎提供了这种确切的行为 - 因为它只是如此充满了问题.)

也就是说,例如Guava Cache所做的是它暴露了一个Map<K, V> asMap() 视图,这是你可以做的事情.这样可以在Map不影响类型安全的情况下为您提供大部分优势.

  • 你......应该考虑使用Guava的`Cache`.它用于谷歌制作,所以它经过了大量的测试和优化,它有[很多](http://code.google.com/p/guava-libraries/wiki/CachesExplained)方便的功能. (5认同)