创建通用映射以使用相同的参数类型保存类型的键和值

时间:2015-10-08 06:49:54

标签: java generics

我有一个由两个类实现的接口

interface I {}
class A implements I {}
class B implements I {}

现在我想创建一个映射,该映射可以将key作为使用I实现的任何对象的Class,并将value作为该Class的Object。所以我可以这样做:

map.put(A.class, new A());
map.put(B.class, new B());

以下所有案例都应该给出错误:

map.put(A.class, new B());
map.put(I.class, new B());

以下Map以这种方式无效:

Map<Class<? extends I>, ? extends I> map;

因为第一次捕获与第二次捕获不同。我怎样才能获得所需的地图?

3 个答案:

答案 0 :(得分:1)

怎么样?
interface I {
}

class A implements I {
}

class B implements I {
}

public class Example {
    public static <T extends I, M extends Map<Class<T>, T>> void put(M map, Class<T> key, T value) {
        map.put(key, value);
    }

    public static void main(String[] args) {
        Map map = new HashMap<Class<I>, I>();
        put(map, A.class, new A());
        put(map, A.class, new B());  // error
        put(map, B.class, new A());  // error
        put(map, B.class, new B());
    }
}

如果你不介意在运行时出错,你可以这样做:

interface I {
}

class A implements I {
}

class B implements I {
}

public class MyMap implements Map<Class<? extends I>, I> {
    private final Map<Class<? extends I>, I> map;

    public MyMap(Map<Class<? extends I>, I> map) {
        this.map = map;
    }

    public int size() {
        return map.size();
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return map.containsValue(value);
    }

    public I get(Object key) {
        return map.get(key);
    }

    public I put(Class<? extends I> key, I value) {
        assert key.getClass().isAssignableFrom(value.getClass());
        return map.put(key, value);
    }

    public I remove(Object key) {
        return map.remove(key);
    }

    public void putAll(Map<? extends Class<? extends I>, ? extends I> m) {
        map.putAll(m);
    }

    public void clear() {
        map.clear();
    }

    public Set<Class<? extends I>> keySet() {
        return map.keySet();
    }

    public Collection<I> values() {
        return map.values();
    }

    public Set<Entry<Class<? extends I>, I>> entrySet() {
        return map.entrySet();
    }

    public static void main(String[] args) {
        MyMap map = new MyMap(new HashMap<Class<? extends I>, I>());
        map.put(A.class, new A());
        map.put(A.class, new B());  // runtime error
        map.put(B.class, new A());  // runtime error
        map.put(B.class, new B());
    }
}

如果map实现Map,则无法获得此类编译时错误:

    put(map, A.class, new A());
    put(map, A.class, new B());  // error
    put(map, B.class, new A());  // error
    put(map, B.class, new B());

这是因为无法使用V接口将K指定为依赖Map。您将不得不为客户端提供具有运行时错误并实现Map的类,或者具有编译时错误的类,并且不实现Map。

答案 1 :(得分:0)

此代码是否解决了您的目的?

import java.util.*;

public class Test {
Map< Class<? extends I>,  I> map = new HashMap < Class<? extends I>, I>();
public static void main(String args[]){
    Test t = new Test();
    t.addMaps();

}
private void addMap(I obj){
    map.put(obj.getClass(),obj);
}
private void addMaps(){
    addMap(new A());
    addMap(new B());
    System.out.println(map);
}

}
interface I {}
class A implements I {}
class B implements I {}
class C{};

答案 2 :(得分:-1)

ClassToInstanceMap在Guava中完全符合您的要求,并且是类型安全的。