民间,
是否有任何简单的方法可以在非泛型类中添加泛型类。
基本上,缓存管理器将具有Cache类的映射,该类使用适当的泛型实现。
但是在下面的类中我们返回(getCache方法)通过get方法缓存它需要在调用者处显式强制转换如何避免它。
e.g。
public class CacheManager {
private Map<String, Cache<?,?>> cacheMap = new HashMap<String, Cache<?,?>>();
public Cache<?,?> getCache(String cacheName) {
return cacheMap.get(cacheName);
}
public void addCache(String cacheName,Cache<?,?> cache) {
cacheMap.put(cacheName, cache);
}
}
答案 0 :(得分:0)
简短回答:不(据我所知)。
这里的问题是你所做的事情在Java中根本不是类型安全的。看看这个例子:
import java.util.*;
class ClassCast {
public static void main(String[] args) {
HashMap<String, Pair<?, ?>> map = new HashMap<>();
map.put("test", new Pair<String, Integer>("Hello", 5));
Pair<Double, Double> pair = (Pair<Double, Double>) map.get("test");
}
}
class Pair<T,V> {
T a;
V b;
Pair(T a, V b) {
this.a = a;
this.b = b;
}
}
你会期望ClassCastException
在这里,但它编译并运行完全正常。这样做的原因是实际的Pair<String, Integer>
和Pair<Double, Double>
类实际上只是Pair
(在类型擦除之后)。
要获得类型安全,您必须实现“Typesafe异构容器模式”(Josh Bloch在Effective Java中详细解释)。简而言之,您必须将type参数包含在地图的键中。根据您的需要,您可以直接使用类作为键,否则您可能必须创建一个关键对象。
示例实施:
public class CacheManager {
private Map<MultiKey, Cache<?,?>> cacheMap = new HashMap<>();
@SuppressWarnings("unchecked")
public <T,V> Cache<T,V> get(String name, Class<T> t, Class<V> v) {
// Type-safe since types are encoded in key(i.e. map will not
// return something with the wrong type), and key is type-checked
// on insertion.
return (Cache<T,V>) cacheMap.get(new MultiKey(name, t, v));
}
public <T,V> void put(String name, Class<T> t, Class<V> v, Cache<T,V> cache) {
cacheMap.put(new MultiKey(name, t, v), cache);
}
class MultiKey {
Object[] keys;
Integer hash = null;
MultiKey(Object... keys) {
this.keys = keys;
}
@Override
public int hashCode() {
if (hash == null) hash = Arrays.hashCode(keys);
return hash;
}
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof MultiKey)) return false;
return Arrays.equals(keys, ((MultiKey) o).keys);
}
}
}
使用示例:
CacheManager mng = new CacheManager();
mng.addCache("SI", String.class, Integer.class, new Cache<String, Integer>());
Cache<String, Integer> cache = mng.getCache("SI", String.class, Integer.class);
System.out.println(cache);
它不漂亮,但它实际上是类型安全的。它可以根据实际情况进行改进,因此您不应该按原样使用此代码。例如,如果您可以从Cache对象中获取类型,则不需要addCache
中的Class参数。