2011-11-10 9 views
4

質問のタイトルははっきりしないと思いますが、そのアイデアは簡単です。Java Mapインターフェイスでジェネリック型パラメータの値をどのように関連付けることができますか?

マップ型の変数があるとします。

Map<K,V> myMap; 

が、私は、たとえばKとVの間の関係を確立したい、私は この地図は、そのクラスのオブジェにいくつかのクラスのセットを関連付けることを言いたいです。何かのように:私は

(Set<String>, String), 
(Set<Integer>, Integer) 
... 

のようなエントリを受け入れるために、この地図が欲しい、特定のタイプのT.ため

Map<Set<T>, T> myMap; 

ではなく、私はこの振る舞いを持つことができますMYMAPのための可能な宣言がありますか?私が間違って自分自身を説明しているのか、以前の概念上の誤りがあるのか​​どうか教えてください。

+0

は、あなたが期待しているが、その入れた後、空の '設定し'が続く中で、空の 'を設定します'空の 'Set 'はマップされないか、 'String'を返します(' ClassCastException'を投げます)? –

答えて

0

コンパイラにput()コールごとに異なるTを確認させる方法はありません。言い換えれば、あなた同じマップを持って行うことはできません。

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()方法を有していなければならないことを忘れないでください

さて、あなたは間違いのような何かを行うことができますa Set

+0

nice!私はこれを解決するための名前付きクラスを作成することを考えなかった。パフォーマンスの問題を心配する必要はありません.Setの設定は単なる例であり、私のユースケースは異なります。 –

+0

これは、同じタイプのキーと値のペアを強制します。私が理解するように、OPは、値がキーのセットと同じタイプを持つ単一のマップに異なるタイプのキーと値のペアを配置できるようにしたいと考えています。タイプはクラスではなく個々のメソッドで定義されています。 – BalusC

+1

私が望む限り、彼が望むマップはStringとIntegerの両方のエントリを含むことができますが、マッピングは一致する必要があります。 Set Integer to IntegerおよびString to Stringを設定できますが、同じマップに両方のタイプを含めることができます。 – Stefan

1

それぞれの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 
    } 
} 
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 

} 

がここにあります:put

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); 

第二には、例外がスローされます。

しかし、両方の実装(と私はそれが空のためにキーとして失敗することを意味しない)と使用/ APIはアラームベルをトリガします...本当にそのような構造に対処したいですか?おそらくあなたはあなたの問題を再考する必要がありますか?あなたは何ですか実際にを達成しようとしていますか?

+0

正確な実行時の実装の種類と一致させたくないと思います。 –

+0

あなたはそうです、OPはいつでも 'valueType.isAssignableFrom(keyElementType)'を使うことができます。 –

2

悲しいことに、これはJavaジェネリックでは不可能です。代わりに、実際のjava.util.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); 
    ... 
} 

public interface Map<K, V> { 
    V put(K key, V value); 
    ... 
} 

あなたは問題がKが宣言されていることであることがわかりますJavaは高次型パラメータを許可された場合は、1のようなMap何かを定義している可能性が1回はクラス全体で、.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); 
    } 
} 
関連する問題