[英]How can I define in JAVA generic type that extends Map object with 2 generic parameters?
[英]how can I relate values of generic type parameters in java Map interface?
我不認為問題的標題會很清楚,但這個想法很簡單。
假設我有一個Map類型變量。
Map<K,V> myMap;
但是我想建立一個K和V之間的關系,例如,我想說這個Map將某些類的集合與該類的objets相關聯。 就像是:
Map<Set<T>, T> myMap;
但不是特定類型T.我希望這個地圖接受像這樣的條目
(Set<String>, String),
(Set<Integer>, Integer)
...
是否有可能的myMap聲明允許我有這種行為? 如果我錯誤地解釋自己或者我之前有過概念錯誤,請告訴我。
遺憾的是,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);
}
}
你想要做的事情似乎不是一個好的迪亞,因為每個Set<T>
總是不等於另一個Set<T>
即使是相同的類型 - 使用Sets作為鍵或多或少是無用的。
也就是說,您不需要定義新類 - 您可以要求一個方法來接受這樣的地圖:
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
}
}
對於每個put()
調用,編譯器無法使用泛型驗證不同的T
換句話說,你不能擁有相同的地圖並做:
myMap.put(new HashSet<String>(), "foo");
myMap.put(new HashSet<Integer>(), 1);
如果你需要這個,那么你可能必須存儲<Object>
並使用instanceof
或其他一些hack自己進行驗證。
現在,你絕對可以這樣做:
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
可能很昂貴。
我認為用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觸發警鍾......你真的想要處理這樣的結構嗎? 也許你需要重新思考你的問題? 你究竟想要實現什么目標?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.