我不认为问题的标题会很清楚,但这个想法很简单。
假设我有一个Map类型变量。
Map<K,V> myMap;
但我想建立K和V之间的关系,例如,我想说 此Map将某些类的集合与该类的objets相关联。类似的东西:
Map<Set<T>, T> myMap;
但不适用于特定类型T.我希望此地图接受
等条目(Set<String>, String),
(Set<Integer>, Integer)
...
是否有可能的myMap声明允许我有这种行为?如果我错误地解释自己或者我之前有过概念错误,请告诉我。
答案 0 :(得分:2)
遗憾的是,Java泛型不可能实现这一点。如果Java允许更高阶类型参数,那么可以定义Map
之类的内容:
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);
...
}
而不是实际的java.util.Map
:
public interface Map<K, V> {
V put(K key, V value);
...
}
您可以看到问题是K
为整个班级宣布一次,而不是每次拨打.put()
。
足够的幻想,你能做什么?我认为最好是创建一个Map<Set<?>, Object>
并将其作为私人成员包装。然后,您可以自由创建自己的put()
和get()
,其中考虑了类型之间的预期“关系”:
class SpecialMap {
private Map<Set<?>, Object> map = ...;
public <T>
T put(Set<T> key, T value) {
return (T) map.put(key, value);
}
public <T>
T get(Set<T> key) {
return (T) map.get(key);
}
}
答案 1 :(得分:1)
你要做的事情似乎不是一个好的死亡,因为每个Set<T>
总是不等于另一个Set<T>
,即使是相同的类型 - 使用集合作为键更多或少用无用了。
那就是说,你不需要定义一个新类 - 你可以要求一个方法来接受这样的地图:
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
}
}
答案 2 :(得分:0)
泛型无法让编译器为每个T
调用验证不同的put()
。换句话说,你不能拥有相同的地图并执行:
myMap.put(new HashSet<String>(), "foo");
myMap.put(new HashSet<Integer>(), 1);
如果您需要,则可能需要存储<Object>
并使用instanceof
或其他一些黑客进行验证。
现在,您肯定可以做类似的事情:
public class MyMap<T> extends HashMap<Set<T>, T> {
...
然后你可以这样做:
MyMap<String> myMap = new MyMap<String>();
Set<String> set = new HashSet<String>();
myMap.put(set, "foo");
请注意,密钥必须包含有效的hashCode()
和equals()
方法,Set
可能会很昂贵。
答案 3 :(得分:0)
我认为用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
}
以下是它的工作原理:
final Map<Set<? extends Object>, Object> map =
new FancyTypeMapDecorator(new HashMap<Set<? extends Object>, Object>());
Set<? extends Object> keyA = Collections.singleton(7);
map.put(keyA, 42);
Set<? extends Object> keyB = Collections.singleton("bogus");
map.put(keyB, 43);
第二个put
会抛出异常。
然而这两个实现(我甚至不认为它会因空Set
作为键而失败)而且usage / API会触发警钟......你真的想要处理这样的问题吗?结构体?也许你需要重新思考你的问题?你实际试图实现什么?