2017-03-14 14 views
0

継承を使用してクラスコンストラクタでリフレクションを作成する際に問題が発生しました。具体的には、すべての属性値を取得したいと考えています。ここで継承を持つコンストラクタでのリフレクション(Java)

は動作しませんナイーブな実装のためのデモです:

import java.lang.reflect.Field; 

public class SubInitProblem { 
    public static void main(String[] args) throws IllegalAccessException { 
    Child p = new Child(); 
    } 
} 

class Parent { 
    public int parentVar = 888888; 

    public Parent() throws IllegalAccessException { 
    this.showFields(); 
    } 

    public void showFields() throws IllegalAccessException { 
    for (Field f : this.getClass().getFields()) { 
     System.out.println(f + ": " + f.get(this)); 
    } 
    } 
} 

class Child extends Parent { 
    public int childVar = 999999; 

    public Child() throws IllegalAccessException { 
    super(); 
    } 
} 

これはchildVarがゼロであることが表示されます:

public int Child.childVar: 0 
public int Parent.parentVar: 888888 

それはまだ初期化されていませんだから。

だから私は、私が直接コンストラクタを使用しないようにする必要がありますね、ではなく、コンストラクタが完了してみましょうとその後、使用showFields

import java.lang.reflect.Field; 

public class SubInitSolution { 
    public static void main(String[] args) throws IllegalAccessException { 
    SolChild p = SolChild.make(); 
    } 
} 

class SolParent { 
    public int parentVar = 888888; 

    protected SolParent() { 
    } 

    public static <T extends SolParent> T make() throws IllegalAccessException { 
    SolParent inst = new SolParent(); 
    inst.showFields(); 
    return (T) inst; 
    } 

    public void showFields() throws IllegalAccessException { 
    for (Field f : this.getClass().getFields()) { 
     System.out.println(f + ": " + f.get(this)); 
    } 
    } 

} 

class SolChild extends SolParent { 
    public int childVar = 999999; 

    public SolChild() throws IllegalAccessException { 
    } 
} 

をしかしmakeが戻らないので、それが動作しません。サブクラスの正しい型。 (だから問題はnew SolParent();です)。

これを解決する最良の方法は何ですか? showFieldsを実行するためにはすべてのサブクラスが必要ですが、明示的にそれに頼ることはできません。後者は唯一の公共フィールドを処理するので、私はないClass.getFields()Class.getDeclaredFields()を、使用

public void showFields() throws IllegalAccessException { 
    Class<?> clz = this.getClass(); 
    while(clz != Object.class) { 
     for (Field f : clz.getDeclaredFields()) { 
      f.setAccessible(true); 
      System.out.println(f + ": " + f.get(this)); 
     } 
     clz=clz.getSuperclass(); 
    } 
} 

注:

+0

2番目の例では、なぜ 'make'メソッドを実装するのですか?なぜ新しいSolChild()を使わないのですか?showFields(); – ToYonos

+3

コンストラクタからそのようなメソッドを呼び出さないでください。それらは初期化に寄与しないため、コンストラクタに属しません。 –

+0

@ ToYonosそれでは、私のクラスを使っている人がそれを忘れるかもしれないので – Mark

答えて

2

あなたshowFields方法は、このような何かをクラス階層を横断する必要があります。


そして、これはあなたが一般的な方法であなたのクラスを構築することができる方法です。SolParentのあなたのサブタイプは、公共引数なしのコンストラクタ(または全くないコンストラクタを持っている場合にのみ動作すること

public static <T extends SolParent> T make(Class<T> type) throws Exception { 
    Constructor<T> constructor = type.getDeclaredConstructor(); 
    constructor.setAccessible(true); 
    T inst = constructor.newInstance(); 
    inst.showFields(); 
    return inst; 
} 

は注意まったく)。

+2

'make'はまだ子ではなく親のインスタンスを作成します。 – assylias

+1

@assylias良い点。追加されたインスタンス化コード –

+0

それは意味があるが、私はそれが問題だとは思わない。親の属性はすでに見つかっており、子の属性はまだ初期化されていません。編集:あなたの編集について、私は 'クラスタイプ'が何であるかわからない、それを見て、戻ってくる – Mark

関連する問題