如何在java映射接口中关联泛型类型参数的值?

如何在java映射接口中关联泛型类型参数的值?,java,generics,types,map,Java,Generics,Types,Map,我不认为这个问题的标题会很清楚,但想法很简单 假设我有一个映射类型变量 Map<K,V> myMap; Map-myMap; 但是我想在K和V之间建立一个关系,例如,我想说 此映射将某个类的集合与该类的对象相关联。比如: Map<Set<T>, T> myMap; public class MyMap<T> extends HashMap<Set<T>, T> { ... public interface M

我不认为这个问题的标题会很清楚,但想法很简单

假设我有一个映射类型变量

Map<K,V> myMap;
Map-myMap;
但是我想在K和V之间建立一个关系,例如,我想说 此映射将某个类的集合与该类的对象相关联。比如:

Map<Set<T>, T> myMap;
public class MyMap<T> extends HashMap<Set<T>, T> {
    ...
public interface Map<V<>> {  // here V<> is my hypothetical syntax for a 
                             // type parameter which is itself generic...
    <K>
    V<K> put(K key, V<K> value);
    ...
}
Map-myMap;
但不是针对特定类型的T。我希望此映射接受以下条目

(Set<String>, String),
(Set<Integer>, Integer)
...
(集合,字符串),
(集合,整数)
...

myMap是否有允许我进行此行为的可能声明?请让我知道我是否在错误地解释自己,或者我之前是否有概念上的错误

泛型无法让编译器为每个
put()
调用验证不同的
T
。换句话说,您不能拥有相同的地图并执行以下操作:

myMap.put(new HashSet<String>(), "foo");
myMap.put(new HashSet<Integer>(), 1);
然后你可以做:

MyMap<String> myMap = new MyMap<String>();
Set<String> set = new HashSet<String>();
myMap.put(set, "foo");
MyMap MyMap=newmymap();
Set=newhashset();
myMap.put(set,“foo”);

请记住,密钥必须具有有效的
hashCode()
equals()
方法,这些方法对于
Set

来说可能会很昂贵,您试图做的似乎不是一个好的diea,因为每个
集合
总是不等于另一个
集合
,即使是同一类型的,使用集合作为键或多或少是无用的

也就是说,您不需要定义新类-您可以要求一个方法来接受这样的映射:

public static <T> void process(Map<Set<T>, T> map) {
    for (Map.Entry<Set<T>, T> entry : map) {
        Set<T> key = entry.getKey();
        T value = entry.getValue();
        // do something
    }
}
公共静态作废流程(Map){
for(Map.Entry:Map){
Set key=entry.getKey();
T value=entry.getValue();
//做点什么
}
}

我认为不可能用Java泛型实现编译时检查。然而,它在运行时非常简单。正好是一个简短的装饰师:

public class FancyTypeMapDecorator implements Map<Set<? extends Object>, Object> {

    final Map<Set<? extends Object>, Object> target;

    public FancyTypeMapDecorator(Map<Set<? extends Object>, Object> target) {
        this.target = target;
    }

    @Override
    public Object put(Set<? extends Object> key, Object value) {
        final Class<?> keyElementType = key.iterator().next().getClass();
        final Class<?> valueType = value.getClass();
        if (keyElementType != valueType) {
            throw new IllegalArgumentException(
                "Key element type " + keyElementType + " does not match " + valueType);
        }
        return target.put(key, value);
    }

    @Override
    public void putAll(Map<? extends Set<? extends Object>, ? extends Object> m) {
        for (Entry<? extends Set<? extends Object>, ? extends Object> entry : m.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    //remaining methods are simply delegating to target

}
公共类FancyTypeMapDecorator实现MapKeyElementType=key.iterator().next().getClass(); 最终类valueType=value.getClass(); if(keyElementType!=valueType){ 抛出新的IllegalArgumentException( “关键元素类型”+keyElementType+“与”+valueType”不匹配); } 返回目标、投放(键、值); } @凌驾
public void putAll(Map遗憾的是,这在Java泛型中是不可能的。如果Java允许更高阶的类型参数,那么可以定义
Map
类似的内容:

Map<Set<T>, T> myMap;
public class MyMap<T> extends HashMap<Set<T>, T> {
    ...
public interface Map<V<>> {  // here V<> is my hypothetical syntax for a 
                             // type parameter which is itself generic...
    <K>
    V<K> put(K key, V<K> value);
    ...
}
您可以看到,问题在于
K
只为整个类声明一次,而不是每次调用
.put()

幻想够了,那你能做什么呢?我认为最好是创建一个
Map,Object>Map=。。。;
公开的
T输入(设置键,T值){
返回(T)map.put(键、值);
}
公开的
T获取(设置关键点){
return(T)map.get(key);
}
}

nice!我没有想到创建一个命名类来解决这个问题。不要担心性能问题,集合只是一个例子,我的用例不同。这仍然迫使您放置相同类型的键值对。据我所知,OP希望能够将不同类型的键值对放置在一个映射中,其中的值是与键集的类型相同。类型不必在类上定义,而是在各个方法上定义。据我所知,他想要的映射可以同时包含字符串和整数项,但映射需要匹配。因此,整数到整数集和字符串到字符串集,但同一映射可以同时包含这两种类型。您希望如何查找值?还是仅用于存储和迭代?我认为您不希望匹配确切的运行时实现类型。您是对的,OP始终可以使用
valueType.isAssignableFrom(keyElementType)
或另一种方式-取决于要求。您是否希望在放入一个空的
后再放入一个空的
,空的
将被取消映射或返回一个
字符串
(/抛出一个
ClassCastException
)?