Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java泛型-映射(类型化)映射_Java_Generics_Caching_Map - Fatal编程技术网

Java泛型-映射(类型化)映射

Java泛型-映射(类型化)映射,java,generics,caching,map,Java,Generics,Caching,Map,我正在研究一种(简单的)缓存解决方案,其中服务可以从缓存映射请求缓存对象。缓存对象的工作原理也与映射类似,它有一个键和一个值以及访问和存储对象的方法 我提出了以下解决方案,但正如您所看到的,它包含一个强制转换(因为get()不知道嵌套对象的类型应该是什么) private final Map>(); 公共缓存getOrCreateCache(字符串标识符){ if(缓存.容器(标识符)){ 返回(缓存)缓存。获取(标识符); }否则{ Cache Cache=new CacheImpl(); c

我正在研究一种(简单的)缓存解决方案,其中服务可以从缓存映射请求缓存对象。缓存对象的工作原理也与映射类似,它有一个键和一个值以及访问和存储对象的方法

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

private final Map>();
公共缓存getOrCreateCache(字符串标识符){
if(缓存.容器(标识符)){
返回(缓存)缓存。获取(标识符);
}否则{
Cache Cache=new CacheImpl();
caches.put(标识符,cache);
返回缓存;
}
}
专用无效测试(){
Cache strCache=getOrCreateCache(“字符串缓存”);
标准设置(“键”、“值”);
}
现在,我的问题是:

  • 只要正确处理ClassCastException,这是一种“安全”的方法吗?(可能会捕获这些异常并将它们打包到自定义异常类中)
  • 有“安全”的替代方案吗?一个是泛型,如果可能的话,因为我喜欢它们,不喜欢类型转换
  • (不直接相关)这是线程安全的吗?我想不会,但我不是线程专家。仅仅使整个方法同步就足够了吗,或者(有六个客户端)会导致太多的开销/锁定吗?有一个简洁的解决方案吗
编辑:哇,有很多答案,谢谢!编辑这里来描述我在实际测试时发现的一个奇怪现象:

    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.
Cache someCache=service.getOrCreateCache(cacheIdentifier);
set(“asdf”、“sdfa”);
Cache somecacheretrievedreach=service.getOrCreateCache(cacheIdentifier);
System.out.println(somecacheretrievedreach.get(“asdf”);//打印“sdfa”。没有任何错误。古怪的

您只需将整个方法同步化,以确保线程安全。如果不经常调用它,它将足够有效。如果您想让代码更安全,我建议您尝试以下方法,为类型添加运行时检查

public <K, V> Cache<K, V> getOrCreateCache(String identifier, Class<K> kClass, Class<V> vClass) {
    Cache<K, V> cache = (Cache<K, V>) caches.get(identifier);
    if(cache == null)
        caches.put(identifier, cache = new CacheImpl<K, V>(kClass, vClass));
    assert cache.kClass() == kClass;
    assert cache.vClass() == vClass;
    return cache;
}
公共缓存getOrCreateCache(字符串标识符、类kClass、类vClass){
Cache Cache=(Cache)caches.get(标识符);
if(缓存==null)
caches.put(标识符,cache=newcacheimpl(kClass,vClass));
assert cache.kClass()==kClass;
断言cache.vClass()==vClass;
返回缓存;
}

您可以创建一个由当前标识符和两个类实例(一个用于键,一个用于值)组成的复合键

公共缓存getOrCreateCache(字符串标识符、类keyClass、类valueClass){
标识符cacheIdentifier=新标识符(标识符、键类、值类);
//安全强制转换,因为我们知道此cacheIdentifier必须具有缓存
Cache Cache=(Cache)caches.get(标识符);
if(缓存==null){
cache=新的CacheImpl();
caches.put(cacheIdentifier,cache);
}
返回缓存;
}
/*
*不是最有效的实现,但正确地实现了hashCode和equals
*这就是我们所需要的
*/
私有静态类CacheIdentifier扩展了ArrayList{
专用缓存标识符(字符串标识符、类keyClass、类valueClass){
超级(3);
//TODO检查是否为空
添加(标识符);
添加(keyClass);
添加(valueClass);
}
}

要使此线程安全,请在线程安全问题上使用a和putIfAbsent(..)

,不,它不是线程安全的。你应该看看或谷歌番石榴

这是一种“安全”的方法吗 在处理ClassCastException时 适当地?(可能会赶上 然后把它们打包成一个定制包 异常类)

实际上,最安全的处理方法是使用key和value类型创建缓存键。大概是这样的:

public String getCacheKey(Class<?> keyType, Class<?> valueType, String uniqueId){
    return keyType.getName()+"-"+valueType.getName()+"-"+uniqueId;
}
公共字符串getCacheKey(类keyType、类valueType、字符串uniqueId){
返回keyType.getName()+“-”+valueType.getName()+“-”+唯一标识;
}
这样,您就可以确保缓存是指定类型的

有“安全”的替代方案吗?一个 如果可能的话,使用泛型, 因为我喜欢他们,不喜欢他们 演员

基本上:如果您不喜欢未经检查的强制转换,则必须为所有方法提供实现类型

(没有直接关系)是这样吗 线程安全?我想不会,但是, 我不是线程专家。它是 足以使整个方法 是同步的,还是(与 六个客户)造成太多 头顶/锁定?有整洁的房间吗 解决方案是什么


同步方法很糟糕。使用a和它的方法

昨天也有类似的情况。您的解决方案是不安全的,因为密钥中没有任何表示值类型的内容。在另一个问题中,键是
Callable
,值是
T
。因此,可以制作一个自定义映射,以确保类型安全,并防止基础映射被损坏。

我喜欢ArrayList的扩展,以快速组成排序标识符,这是一个不错的技巧,应该记住它。我会试试你的解决方案。试过之后:我非常喜欢你的解决方案。尝试检索不同类型的缓存对象时,将返回一个新的缓存对象。优雅的缓存标识符对象也可以永久地存储在客户端中,因为它是不可变的斜杠没有被改变。考虑使用COM.GoGoLe.Cuff.Calc.MMAcKe.MaKeCoMpPug映射线程安全解决方案。如果您希望节省内存和/或时间(不要忘记实现hashCode和equals),请使用自己的类替换ArrayList。
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);
  }
}
public String getCacheKey(Class<?> keyType, Class<?> valueType, String uniqueId){
    return keyType.getName()+"-"+valueType.getName()+"-"+uniqueId;
}