web-dev-qa-db-ja.com

Javaの型消去にもかかわらずT.classを取得する

構成ファイルから読み取ったインターフェイスをその実装にバインドして、IoCコンテナーにフィードできるようにしようとしています。これが私がやろうとしていることの大まかなものです:

public class PropertyImplementationBinder<T> {
    // ...
    public Class getInterfaceClass() {
        return T.class; // OR Class<T>, note T is not newable
    }
    public Class getImplementationClass() {
        return /* read config file to get implementation class */;
    }
}

どういうわけかT.classを取得することは可能ですか?

18
Kaleb Pederson

クラスをコンストラクターに明示的に渡す(そして自分で保存する)必要があります。

private final Class<T> clazz;

PropertyImplementationBinder(Class<T> clazz){
    this.clazz = clazz;
}

public Class<T> getInterfaceClass() {
    return clazz;
}
30
Thilo

クラスのジェネリックスーパークラスの実際の型引数を取得できます。この ブログ投稿 は、些細な匿名の内部クラスを使用したちょっとしたトリックなど、これによって提示される可能性を探ります。直接引用するには:

JVMはジェネリッククラスのインスタンスの実際の型引数を追跡しませんが、の実際の型引数を追跡することがわかりました。 サブクラス ジェネリッククラスの。言い換えると、実行時のnew ArrayList<String>()は実際には単なるnew ArrayList()ですが、クラスがArrayList<String>を拡張する場合、JVMはStringListの型パラメーターの実際の型引数。

9
kloffy

広く受け入れられているものとは異なり、ほとんど知られていない型消去を回避できます。つまり、呼び出し先は、呼び出し中に使用された汎用パラメーターを知ることができます。

以下をご覧ください: TypeTokenを使用してジェネリックパラメーターを取得する

この記事では、このテクニックを使用したユーザーの体験についても説明しています。一言で言えば、私たちはフォールバックすることになりました...

従来の広く使用されている手法: "コンストラクターでクラス型を渡す"

5
Richard Gomes

ところで。 @Richard Gomesの記事にある静的メソッドgetTypeの例には、2つのエラーがあります。次のようになります。

static public Class<?> getType(final Class<?> klass, final int pos) {
    // obtain anonymous, if any, class for 'this' instance
    final Type superclass = klass.getGenericSuperclass();

    // test if an anonymous class was employed during the call
    if ( !(superclass instanceof ParameterizedType) ) {
            throw new RuntimeException("This instance should belong to an anonymous class");
    }

    // obtain RTTI of all generic parameters
    final Type[] types = ((ParameterizedType) superclass).getActualTypeArguments();

    // test if enough generic parameters were passed
    if ( pos >= types.length ) {
            throw new RuntimeException(String.format("Could not find generic parameter #%d because only %d parameters were passed", pos, types.length));
    }

    if (!(types[pos] instanceof Class<?>)) {
            throw new RuntimeException("Generic type is not a class but declaration definition(all you get is \"[T]\") " + types[pos]);
    }
    // return the type descriptor of the requested generic parameter
    return (Class<?>) types[pos];
}

残念ながら、コードに明示的に含まれている場合は機能するため、まだ魔法の弾丸ではありません

getType(new SomeObject<String>(){}.class, 0) // you get String.class

しかし、あなたがこれを次のようなもので呼ぶなら

getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it

Tという名前を付けてください。

1
durilka