2011-09-05 5 views
9

私のようにスーパークラスを持っている:私はスーパークラスの実装java.lang.Object getValue()の両方を取得サブクラスでオーバーライドされたときにリフレクトを介して基本クラスのメソッドを取得するのはなぜですか?

Class clazz = MyClassImpl.class; 
Method[] methods = clazz.getDeclaredMethods(); 

void setValue(java.lang.Object)と:その後、私のようにAA特定の派生MyClassImpl上の反射に

class MyClassImp extends MyClass<String> { 
    @Override 
    public void setValue(String value){ 
    //insert code 
    } 

    @Override 
    public String getValue(){ 
    return null; 
    } 
} 

を持って

class MyClass<T> { 
    public void setValue(T value){ 
    //insert code 
    } 

    public T getValue(){ 
    return null; 
    } 
} 

java.lang.String getValue(),void setValue(java.lang.String)

Class.getDeclaredMethods()のJavaドキュメントによればVIS-すなわち

このオブジェクトが表すクラスまたはインタフェースによって宣言されたすべてのメソッドを反映するMethodオブジェクトの配列を返します。これには、public、protected、default(パッケージ)アクセス、およびprivateメソッドが含まれますが、継承されたメソッドは除きます。返される配列の要素はソートされず、特定の順序ではありません。クラスまたはインタフェースがメソッドを宣言しない場合、またはこのClassオブジェクトがプリミティブ型、配列クラス、またはvoidを表す場合、このメソッドは長さ0の配列を返します。クラスの初期化メソッド<clinit>は、返される配列には含まれません。クラスが同じパラメータ型を持つ複数のパブリックメンバメソッドを宣言する場合、それらはすべて返された配列に含まれます。

なぜ私はスーパータイプの実装を取得していますか? 私には何かがありますか?

私が必要とするのは、基底クラスの実装で反射的にsetValueを呼び出すことです。これには、特別な注釈コメントと追加の制約が追加されています。

+1

http:// stackoverflowの重複がある可能性があります。com/questions/5756081/java-generics-reflection –

+1

@RC:どのようにその質問の重複があるのか​​わかりません。 –

+0

@RCこれは正確な複製ではありません – amod

答えて

13

実際にコンパイルされたクラスはです。setValue(Object)と宣言しています。このメソッドはStringにキャストし、厳密に型指定されたメソッドを呼び出します。同様にgetValue(Object)getValue(String)を呼び出します。

JVMは実際にジェネリックを知らないので(少なくとも深いところでは)、JVMレベルでスーパークラスメソッドをオーバーライドするには、同じシグネチャを持たなければならないため、必須です。ジョンは型情報がジェネリックため、実行時に失われた、先に述べたとおり

public java.lang.Object getValue(); 
    Code: 
    0: aload_0 
    1: invokevirtual #3; //Method getValue:()Ljava/lang/String; 
    4: areturn 

public void setValue(java.lang.Object); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: checkcast  #4; //class java/lang/String 
    5: invokevirtual #5; //Method setValue:(Ljava/lang/String;)V 
    8: return 

} 
+4

'Method.isSynthetic()'は、 'Object'を受け取って返す生成されたメソッドに対して' true'を返すことに注意してください。これは、これらのメソッドを「実際の」メソッドと区別する良い方法です。 –

+0

このコンパイラの動作はどこかに書かれていますか? –

+0

@ライアン:わかりません、私は恐れています。 JLSについて簡単に見てもわかりませんが、このような状況はいくつかの箇所で言及されています。 –

1

あなたは、余分な合成法を参照してくださいよjavap -c MyclassImpでクラスを見てください。

したがって、ジェネリックを使用するたびに、コンパイラはそれらのすべての継承された「汎用」メソッドをサブクラスに配置します。同じことは非ジェネリックコードでは当てはまりません。

スーパークラスから一般的な関連コード(<T>の部分)を削除したとき、リフレクションコードは、オーバーライドしてもサブクラスに正確に2つのメソッドを与えました。これは、ドキュメンテーションがジェネリック関連のコードに対して少し明白であったはずであることを意味します。

+0

厳密に言えば、それらのメソッドはジェネリック(あなたが気づいたように)のためにそこにはありません。これらのメソッドは、戻り値の型共分散を使用するため(つまり、サブクラスが基本型よりも特定の値を返すため)、そこにあります。それはジェネリックスと組み合わせて使用​​される*最も頻繁に使用されますが、スタンドアロンで使用できます。 –

+0

はい!私はちょうど確認した。 – Santosh

+0

はい私はすべてのシナリオを検証しました。ここでは、私はジェネリックフォームと明示的フォームでオーバーライドします。一般的な形では、私は共分散を持つ2つの方法しか持っていません、私は2つの追加の方法に気づいて、それらは合成としてマークされています – maress

関連する問題