Java泛型 – (类型)映射的映射

我正在研究一种(简单的)缓存解决方案,其中服务可以从缓存地图请求缓存对象. Cache对象基本上就像Map一样,使用键和值以及访问和存储对象的方法.

我提出了以下解决方案,但正如您所看到的,它包含一个强制转换(因为get()无法知道嵌套对象的类型应该是什么).

private final  Map<String, Cache<?, ?>> caches = new HashMap<String, Cache<?, ?>>();

public <K, V> Cache<K, V> getOrCreateCache(String identifier) {
    if (caches.containsKey(identifier)) {
        return (Cache<K, V>) caches.get(identifier);
    } else {
        Cache<K, V> cache = new CacheImpl<K, V>();
        caches.put(identifier, cache);
        return cache;
    }
}

private void test() {
    Cache<String, String> strCache = getOrCreateCache("string cache");
    strCache.set("key", "value");
}

现在,我的问题:

>只要正确处理classcastexceptions,这是一种“安全”的方法吗? (可能会捕获它们并将它们打包成自定义异常类)
>有“安全”选择吗?一个人用泛型,如果可能的话,因为我喜欢他们而不喜欢演员.
>(不直接相关)这是线程安全吗?我假设没有,但那时,我不是线程专家.仅仅使整个方法同步,或者那个(有六个客户端)导致过多的开销/锁定是否足够?那有一个很好的解决方案吗?

编辑:哇,很多答案,谢谢!在这里编辑以描述我在实际测试时发现的奇怪现象:

    Cache<String, String> someCache = service.getOrCreateCache(cacheIdentifier);
    someCache.set("asdf", "sdfa");
    Cache<String, Integer> someCacheRetrievedAgain = service.getOrCreateCache(cacheIdentifier);
    System.out.println(someCacheRetrievedAgain.get("asdf")); // prints "sdfa". No errors whatsoever. Odd.

最佳答案 您可以创建一个复合键,其中包含您当前的标识符和两个Class实例(一个用于键,一个用于值)

public <K, V> Cache<K, V> getOrCreateCache(String identifier, Class<K> keyClass, Class<V> valueClass) {
  Identifier cacheIdentifier = new Identifier(identifier, keyClass, valueClass);
  // safe cast as we know that this cacheIdentifier must has a Cache<K, V>
  Cache<K, V> cache = (Cache<K, V>) caches.get(identifier);
  if (cache == null) {
    cache = new CacheImpl<K, V>();
    caches.put(cacheIdentifier, cache);
  }
  return cache;
}

/*
 * not the most efficient implementation, but correctly implements hashCode and equals
 * which is all we need
 */
private static class CacheIdentifier extends ArrayList<Object> {
  private CacheIdentifier(String identifier, Class<K> keyClass, Class<V> valueClass) {
    super(3);
    // TODO check for null
    add(identifier);
    add(keyClass);
    add(valueClass);
  }
}

要使此线程安全,请使用ConcurrentHashMap而不是putIfAbsent(..)

点赞