6

私はC#の世界から来ましたが、Javaでの消去について学んだばかりなので、少し戸惑いました。JavaのランタイムとSomeGenericInstance<String>区別する方法は本当にありませんか?SomeGenericInstance<Integer>

非常に単純なpub-subフレームワークを実装し、汎用クラスが必要だったため、質問していGenericMessage<T>ます。GenericMessage<String>のリスナーに送信しないことが重要ですGenericMessage<Integer>Classキーがメッセージのタイプを表すオブジェクトであるキーと値のペアのリストを作成して、実装してみました。しかし、このコード行trueは問題を生み出します...:

new GenericMessage<Integer>().getClass.equals(new GenericMessage<String>().getClass())

4

5 に答える 5

2

私の知る限り、申し訳ありませんが、それは不可能です。

于 2013-03-27T13:42:20.303 に答える
2

JavaReflectionを使用してそれを行うことができます。それが常に良い考えであるかどうかはわかりませんが、それは確かに可能です。次に例を示します。

public class Test{

    private List<String> list;

    public static void main(String[] args) throws Exception{
        Field field = Test.class.getDeclaredField("list");
        Field f = field.getGenericType().getClass().getDeclaredField("actualTypeArguments");
        f.setAccessible(true);
        Type[] genericTypes = (Type[]) f.get(field.getGenericType());
        System.out.println(genericTypes[0]);
    }

}

または、パラメータ化されたタイプに直接キャストすることもできます。

public class Test{

    private List<String> list;

    public static void main(String[] args) throws Exception{
        Field field = Test.class.getDeclaredField("list");
        ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
        Type[] actualTypes = parameterizedType.getActualTypeArguments();
        System.out.println(actualTypes[0]);
    }

}

どちらの例も次のように出力します。class java.lang.String

より完全な答えを残すために、マップについても同じことができます。ご覧のとおり、getActualTypeArguments()メソッドはaType[]を返し、 Mapの場合、キータイプはインデックス0になり、値タイプはインデックス1になります。例:

public class Test{

    private Map<String, Integer> map;

    public static void main(String[] args) throws Exception{
        Field mapField = Test.class.getDeclaredField("map");
        ParameterizedType mapParameterizedType = (ParameterizedType) mapField.getGenericType();
        Type[] actualMapTypes = mapParameterizedType.getActualTypeArguments();
        System.out.println(actualMapTypes[0]);
        System.out.println(actualMapTypes[1]);
    }

}

プリント:

class java.lang.String
class java.lang.Integer
于 2013-03-27T13:46:05.180 に答える
2

次のトリックを使用してアクセスできます。

public class Example<T> {

    Class<T> genericType;

    public Example(Class<T> genericType) {
        this.genericType= genericType;
    }

    public static void main(String args[]) {
        Example<Integer> ex1 = new Example<>(Integer.class);
        Example<String> ex2 = new Example<>(String.class);
        System.out.println(ex1.genericType);
        System.out.println(ex2.genericType);
    }
}

出力:

クラスjava.lang.Integer

クラスjava.lang.String

于 2013-03-27T13:47:43.633 に答える
1

リフレクションを使用せずに探しているものを取得する方法は次のとおりです(Classトークンを渡すためにpub-subフレームワークに変更を加えることができると仮定します)。クラスリテラルの方向に私を向けてくれたassyliasとzvzdhkへの大きな帽子のヒント。

interface GenericMessage<T> {

}

interface StringMessage<T extends String> extends GenericMessage<T> {
    String getString();
}

interface IntMessage<T extends Integer> extends GenericMessage<T> {
    int getInt();
}

interface MessageListener<T> {
    <T> void handleMessage(Class<T> type, GenericMessage<T> instance);
}

// "marker interfaces"
interface StringMessageListener<T extends String> extends MessageListener<T> {

}

interface IntMessageListener<T extends Integer> extends MessageListener<T> {

}

class IntMessageImpl<T extends Integer> implements IntMessage<T> {
    public int getInt() {
        return 0;
    }
}

class StringListenerImpl<T extends String> implements StringMessageListener<T> {

    public <T> void handleMessage(Class<T> type, GenericMessage<T> genericMessage) {
        StringMessage stringMessage = (StringMessage) genericMessage; // Typesafe cast since T extends String on both StringMessage and StringMessageListener
        String message = stringMessage.getString();
        // Do something with message
    }
}

class IntListenerImpl<T extends Integer> implements IntMessageListener<T> {
         // an implementation for the Integer case ...
}

void showTypeChecking() {

    GenericMessage<String> badStringMessage = new IntMessageImpl<>(); // Compile-time check fails due to bad type of new message implementation

    MessageListener<Integer> badIntListener = new StringListenerImpl<>(); // Compile-time check fails due to bad type on new listener implementation

    MessageListener<String> stringListener1 = new StringListenerImpl<>();
    MessageListener<String> stringListener2 = new StringListenerImpl<>();
    MessageListener<Integer> intListener = new IntListenerImpl<>();

    GenericMessage<String> stringMessage = new GenericMessage<String>() {};
    stringListener1.handleMessage(String.class, stringMessage);
    stringListener1.handleMessage(Integer.class, stringMessage); // Compile-time check fails due to bad type on class literal

    GenericMessage<Integer> intMessage = new GenericMessage<Integer>() {};
    intListener.handleMessage(Integer.class, intMessage);

    GenericMessage<String> badIntMessage = new GenericMessage<String>() {};
    intListener.handleMessage(Integer.class, badIntMessage); // Compile-time check fails due to bad type on intMessage

    GenericMessage uncheckedMessage = new IntMessageImpl();
    intListener.handleMessage(Integer.class, uncheckedMessage); // Compiler issues warning about unchecked assignment of uncheckedMessage argument

    MessageListener uncheckedListener = new StringListenerImpl();
    uncheckedListener.handleMessage(String.class, stringMessage); // Compiler issues warning about an unchecked call to handleMessage() method
}

この場合は直接適用できませんが、タイプセーフな異種コンテナパターンに関するこの説明は、Javaジェネリックについてもう少し学ぶのに役立ちます。それは間違いなく言語の習得が難しい部分の1つです。

于 2013-03-28T05:34:48.820 に答える
0

SomeGenericInstance<String>「オブジェクト」と「SomeGenericInstance<String>オブジェクト」は違いがないため、区別できません。SomeGenericInstance「オブジェクト」だけがあります。

于 2013-03-28T04:50:01.833 に答える