1

次のインターフェースがある場合:

interface MyElementProcessor<T> {
    void doSomethingWith(T element);
    Class<T> getElementClass();
    /* more functions... */
}

のようなジェネリック型にこれを実装したいとしCollection<T>ます。実装方法を教えてくださいgetElementClass()。これまでの私の最善の試みは次のようなものです:

class MyCollectionProcessor<T> implements MyElementProcessor<Collection<T>> {
    public void doSomethingWith(Collection<T> element) { /* ... */ }

    public Class<Collection<T>> getElementClass() {
        // Ugly, but the only way I have found to cast to Class<Collection<T>>:
        return (Class<Collection<T>>) (Object) Collection.class;
    }
}

Class<Collection<T>>Java でリテラルを指定する方法がないことはわかっていますが、Collection.class直接キャストできないのはなぜClass<Collection<T>>ですか? 経由でキャストするよりも良い方法はありObjectますか?

4

3 に答える 3

3

Collection.class を直接キャストできないのはなぜ Class<Collection<T>>ですか?

Collection.classタイプがありClass<Collection>ます。Java は、成功しないことが証明できるため、この型キャストをコンパイルしません。Class<Collection>との両方のサブタイプである型はおそらくありませんClass<Collection<T>>

Generics では、 A と B が異なり、との関係に関係なく、型 (ワイルドカードではない)Foo<A>の場合、 は のサブタイプにはなりません。したがって、 の唯一のサブタイプはです。同様に、 の唯一のサブタイプはです。これらは交差しないため、このキャストが理論的に成功する方法はありません。Foo<B>ABClass<Collection>SubclassOfClass<Collection>Class<Collection<T>>SubclassOfClass<Collection<T>>

オブジェクト経由でキャストするよりも良い方法はありますか?

Class<?>;経由でキャストできます。しかし、それはそれほど良いことではありません:

return (Class<Collection<T>>) (Class<?>) Collection.class;
于 2013-07-24T01:17:06.873 に答える
1

Java ジェネリックの処理のため、Class<List<Integer>>クラスを取得することはできませんが (チェックされていないキャストなしで)、Class<List>orになりますClass<List<?>>
したがって、 でパラメーター化された型を使用している場合は、メソッドを 2 つの例ElementProcessorに変更することをお勧めします。Class<? super T> getElementClass()

interface MyElementProcessor<T> {
    void doSomethingWith(T element);
    Class<? super T> getElementClass();
    /* more functions... */
}

SimpleElementProcessor implements MyElementProcessor<Integer> {
    public void doSomethingWith(Collection<Integer> element) { /* ... */ }

    public Class<Integer> getElementsClass() {
        return Integer.class;
    }
}

CollectionElementProcessor<E> implements MyElementProcessor<Collection<E>> {
    public void doSomethingWith(Collection<Collection<E>> element) { /* ... */ }

    // This works because Class<Collection<?>> is a valid substitute for Class<? super T>
    public Class<Collection<?>> getElementsClass() {
        return (Class<Collection<?>>) Collection.class; // Maybe the cast isn't needed
    }
}



要素クラスの取得に関しては、リフレクションを使用できます。タイプがMyElementProcessor を派生させる場合、次のように取得できます。

for(Type interface :  getClass().getGenericInterfaces()) {
    if(interface instanceof ParameterizedType && ((ParameterizedType) interface).getRawType == MyElementProcessor.class)
        Type myElementsType = ((ParameterizedType) interface).getActualTypeArguments()[0];


これは、派生クラス、つまり、匿名クラスまたは宣言された型に対してのみ機能します。型消去のためにこのように使用すると機能しません(この例はダミーです:これは単なる例です) :

public <T> MyElementProcessor newInstance() {
    return new MyElementProcessor<T> {
        // overridden methods ...
    };
}

このような場合、次のいずれかを行います。

  • ParameterizedType を取得するのではなく、型引数が TypeVariable であり、実際の型の実装を提供しない MyElementProcessor.class を直接取得します。
  • 生の型が MyElementProcessor で、実際の型引数が TypeVariable である ParameterizedType を取得します
于 2013-07-23T16:55:34.777 に答える