2012-05-21 14 views
7

誰かがこの混乱から私を助けることを願っています。Javaジェネリックスのパラメータを渡す

私はこの方法で作られた:キーとして使用するクラスがMyInterfaceにパラメータとして使用するクラスと同じであることを確認するために、T PARAMTER使用さ

public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { 
} 

を。

私はもちろん、キーとは異なるクラス、および対応するMyInterfaceの実装をマップに渡したいと思います。

しかし、タイプパラメータのために構文エラーが発生しても機能しません。ここにコードがあります、私は自己説明的であることを願っています。

import java.util.HashMap; 
    import java.util.Map; 

    public class Test { 

    public static void main(String[] args) { 
     Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); 

    //  Map<Class<Object>, MyInterface<Object>> map = new HashMap<Class<Object>, MyInterface<Object>>(); 

     map.put(Object.class, new MyObjectImpl()); 

     //if I use Map<Class<Object>, MyInterface<Object>> I get a compiler error here 
     //because map<String> is not map<Object> basically 
     map.put(String.class, new MyStringImpl()); 

     //this would be possible using <?>, which is exactly what I don't want 
    //  map.put(String.class, new MyIntegerImpl()); 

     //<?> generates anyways a compiler error 
     myMethod(map); 
    } 

    //use T to make sure the class used as key is the same as the class of the parameter "object" in doSomething 
    public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { 

    } 

    interface MyInterface<T> { 
     void doSomething(T object); 
    } 

    static class MyObjectImpl implements MyInterface<Object> { 
     @Override 
     public void doSomething(Object object) { 
      System.out.println("MyObjectImpl doSomething"); 
     } 
    } 

    static class MyStringImpl implements MyInterface<String> { 
     @Override 
     public void doSomething(String object) { 
      System.out.println("MyStringImpl doSomething"); 
     } 
    } 

    static class MyIntegerImpl implements MyInterface<Integer> { 
     @Override 
     public void doSomething(Integer object) { 
      System.out.println("MyIntegerImpl doSomething"); 
     } 
    } 
} 
+0

クラス名は通常、オーバーエンジニアリング(例えば、それは意味の症状がある(以下の例のように)MapConstraints.constrainedMapを用いることであろうこれは強制できません)。 – Romain

+1

これについては忘れて、これは動作しません。ジェネリックスは同質のマップしか定義できません。エントリごとに何かを強制することはできません。すべてのマップエントリについて同じことを実行するだけです。 –

+0

@Romeよく、実際の名前はそうではなく、ちょうど明確な例を作るためにそれを書きました。しかしあなたのコメントも同様に適用される可能性があります。 1つの実装だけを意味するものは何を意味しますか?3つはありますか? – Ixx

答えて

8
あなたは Mapput()で定義された制約がないので、それを行うことはできません

方法はkeyvalueの間です。

public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) { 
    map.put(clazz, intf); 
} 
その後

、ちょうどregisterInterfaceを呼び出す代わりに、手動で取り込む:あなたのマップが正しく読み込まれていることを保証したい場合は、たとえば、正確さをチェックするいくつかのAPIの背後にあるマップを隠し、(すなわち、このような制約を作成)地図。

+0

map.put(clazz、intf)だと思います。 – Aif

+0

@Aif、感謝致しました。 – npe

0

私はこれが可能であるとは思わない:

Class<T>は今までの値としてT.classを受け入れます。 Class<Object>は、ObjectがStringのスーパークラスであっても、String.classを受け付けません。

このため、Class<T>をキーとするマップは、を1つだけ持つことができ、値はTです。

コンパイラは、パラメータとして明確な値Tを持つマップのみを受け入れます。あなたはそれぞれMap<Class<?>, MyInterface<?>>を書くことができません?異なっていると仮定されます:Tが同じ値を持つことを要求するMap<Class<T>, MyInterface<T>>と一致しません。

これは、myMethodはシングルエントリマップのみを受け入れることになりますが、これは役に立たないようです。

0

変更

public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) { 

} 

にあなたのメソッドのシグネチャは、今あなたの宣言と呼び出しが動作するはずです。..

Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); 
    map.put(Integer.class, new MyIntegerImpl()); 
    map.put(String.class, new MyStringImpl()); 
    map.put(Object.class, new MyObjectImpl()); 
    myMethod(map); 
+0

しかし、このマップでは 'map.put(Integer.class、MyStringImpl());'を実行することができます。これはまさに質問で尋ねられないものです。 Btw、OPはすでに彼の質問でそれを示唆した。 –

3

私が知る限り、Javaで記述したようにマップを宣言することはできません。タイプのチェックや制約の追加しかできません。

グアバは、ClassToInstanceMapで問題に近づくものを提供しています。指定したインタフェースの唯一の実装があるので、これを実行するための1つの方法はImpl` `で終わる

import java.text.ParseException; 
import java.util.HashMap; 
import java.util.Map; 

import com.google.common.collect.MapConstraint; 
import com.google.common.collect.MapConstraints; 

public class Main { 

    interface MyInterface<T> { 
     void doSomething(T object); 

     Class<T> getType(); 
    } 

    static class MyObjectImpl implements MyInterface<Object> { 
     @Override 
     public void doSomething(Object object) { 
      System.out.println("MyObjectImpl doSomething"); 
     } 

     @Override 
     public Class<Object> getType() { 
      return Object.class; 
     } 
    } 

    static class MyStringImpl implements MyInterface<String> { 
     @Override 
     public void doSomething(String object) { 
      System.out.println("MyStringImpl doSomething"); 
     } 

     @Override 
     public Class<String> getType() { 
      return String.class; 
     } 
    } 

    static class MyIntegerImpl implements MyInterface<Integer> { 
     @Override 
     public void doSomething(Integer object) { 
      System.out.println("MyIntegerImpl doSomething"); 
     } 

     @Override 
     public Class<Integer> getType() { 
      return Integer.class; 
     } 
    } 

    public static void main(String[] args) throws ParseException { 

     Map<Class<?>, MyInterface<?>> map = MapConstraints.constrainedMap(new HashMap<Class<?>, Main.MyInterface<?>>(), 
       new MapConstraint<Class<?>, MyInterface<?>>() { 
        @Override 
        public void checkKeyValue(Class<?> key, MyInterface<?> value) { 
         if (value == null) { 
          throw new NullPointerException("value cannot be null"); 
         } 
         if (value.getType() != key) { 
          throw new IllegalArgumentException("Value is not of the correct type"); 
         } 
        } 
       }); 
     map.put(Integer.class, new MyIntegerImpl()); 
     map.put(String.class, new MyStringImpl()); 
     map.put(Object.class, new MyObjectImpl()); 
     map.put(Float.class, new MyIntegerImpl()); //<-- Here you will get an exception 
    } 
} 
+0

+1私の現在の意見では、非常に参考になりますが、他の答えはより一般的です。 – Ixx

関連する問題