2

したがって、依存性注入の初期化の一部である、このような一般的なメソッドがあります。

public static <TS, TI extends TS> void registerTransient(
    Class<TS> serviceClass, Class<TI> implementationClass)
{
    //
}

ある時点で、クラスが必ずしも存在しない場合があることがわかりました。そして、これは複数のオフを注入する実装クラスです(したがって、サービスクラスは実装クラスと同じです)。当然、次のように記述します。

Class<?> clazz = Class.forName("com.acme.components.MyPersonalImplementation");
registerTransient(clazz, clazz);

IDEAにはこれに関する問題はありませんが、javacは次のように文句を言います。

error: method registerTransient in class TestTrash cannot be applied to given types;
required: Class<TS>,Class<TI>
found: Class<CAP#1>,Class<CAP#2>
reason: inferred type does not conform to declared bound(s)
inferred: CAP#2
bound(s): CAP#1
where TS,TI are type-variables:
TS extends Object declared in method <TS,TI>registerTransient(Class<TS>,Class<TI>)
TI extends TS declared in method <TS,TI>registerTransient(Class<TS>,Class<TI>)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ?
CAP#2 extends Object from capture of ?

何が得られますか?このメソッドでは、2番目のパラメーターが最初のパラメーターのサブクラスである必要があります。?たまたまどのクラスであるかに関係なく、それは両方のパラメーターで同じクラスオブジェクトであり、クラスは常にそれ自体から割り当て可能であると私は思いました。これは、javacが2番目のパラメータに使用する2番目のワイルドカードタイプを不必要に発明し、「ああ、ここには2つのワイルドカードがあるので、一方が他方から割り当て可能かどうかわかりません」と言っているようです。

4

2 に答える 2

2

問題はClass<?>、明示的なキャストを介さない限り、他の型にキャストできないことです (実際にはClass<#capture-... of ?>キャプチャ変換中になります)。そのため、コンパイラは、これらのキャプチャの型境界をメソッド定義のパラメーター化された型と (静的に) 一致させることができません。

次のように、最初に Class に明示的にキャストしてみてください。

registerTransient((Class<Object>)clazz, clazz); 

このようにして、コンパイラは Object を拡張する何かにバインドできます(TSただし、それでも警告は発行されます)。ObjectTI

IntelliJ のコンパイラがこれについて文句を言わないという事実は、何らかの最適化が原因であるか、コンパイラのバグでさえある可能性があります。そのように投稿して、返信を待つ必要があります。

わずかに異なるアプローチでチェックしたい場合、以下は「見た目」は問題なくてもコンパイルされません。

public class A {
    static class B {}

    static class C extends B {}

    static <T, R extends T> void method(final Class<T> t, final Class<R> r) {}

    public static final void main(String... args) {
        B b = new B();
        C c = new C();
        Class<?> cb = b.getClass();
        Class<?> cc = c.getClass();
        method(cb, cc);
    }
}

こちらをご覧ください。これは、Java の型システムの並外れた見方を示しています (ただし、非常に密集しています)。

于 2012-01-20T02:15:51.470 に答える
0

あなたが抱えている問題は、JLS 7 §6.5.6.1 Simple Expression Namesに従って、メソッド引数ごとにキャプチャ変換が個別に行われることです。

式名が代入変換またはメソッド呼び出し変換またはキャスト変換の対象となるコンテキストで表示される場合、式名の型は、キャプチャ変換後のフィールド、ローカル変数、またはパラメーターの宣言された型です( §5.1. 10)。

あなたの場合、「式名」は identifierclazzです。コンパイラの出力が示すように、JLS の要求に応じて 2 回キャプチャされています。

これに対処するための一般的な手法は、ワイルドカードを型変数にバインドするヘルパー メソッドを導入することです。

private static <T> void registerTransient(Class<T> serviceAndImplClass)
{
    registerTransient(serviceAndImplClass, serviceAndImplClass);
}

ワイルドカードを使用してこの新しいメソッドを呼び出すと機能します。

Class<?> clazz = Class.forName("com.acme.components.MyPersonalImplementation");
registerTransient(clazz);

コメントでこの回避策について言及したようです。奇妙に思えるかもしれませんが、実際には言語設計者が意図したアプローチです。

于 2013-07-03T03:55:55.340 に答える