7

誰かがこの混乱から私を助けてくれることを願っています。

私はこの方法を作りました:

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

キーとして使用されるクラスがMyInterfaceのパラメーターとして使用されるクラスと同じであることを確認するために、パラメーターTを使用しました。

ここで、もちろん、キーとして異なるクラスのマップと、それに対応する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");
        }
    }
}
4

4 に答える 4

8

と の間Mapの のput()メソッドで定義された制約がないため、これを行うことはできません。マップが適切に入力されていることを確認する (つまり、そのような制約を作成する) 場合は、正確性をチェックする API の背後にマップを隠します。次に例を示します。keyvalue

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

registerInterface次に、マップを手動で設定する代わりに を呼び出すだけです。

于 2012-05-21T12:51:38.387 に答える
3

As far as I know, you cannot declare a Map like you describe in Java. All you can do is performing type checking and/or add constraints.

Guava offers something that approaches your problem with ClassToInstanceMap. So one way to do this would be to use MapConstraints.constrainedMap (like the example below)

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
    }
}
于 2012-05-21T12:55:44.547 に答える
0

私はこれが可能だとは思わない:

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

このため、キーとしてのマップは、 の値に関係なく、キー値としてClass<T>1 つの要素のみを持つことができます。T.classT

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

とは言っても、myMethod は単一エントリ マップしか受け入れないため、役に立たないようです。

于 2012-05-21T12:26:26.643 に答える
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);
于 2012-05-21T12:44:52.740 に答える