在泛型类中添加泛型成员变量

时间:2015-03-31 11:54:08

标签: java generics

民间,

是否有任何简单的方法可以在非泛型类中添加泛型类。

基本上,缓存管理器将具有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);
    }
}

1 个答案:

答案 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参数。