2017-03-14 2 views
0

Ich habe Probleme, die Reflektion in einem Klassenkonstruktor mit Vererbung zu arbeiten. Speziell möchte ich alle Attributwerte erhalten. HierReflektion im Konstruktor mit Vererbung (Java)

ist eine Demo für die naive Implementierung, die nicht funktioniert:

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(); 
    } 
} 

Dies wird zeigen, dass childVar Null:

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

Weil es noch nicht initialisiert ist.

Also ich denke, ich brauche nicht den Konstruktor direkt verwenden, sondern lassen den Konstruktor vollständig und dann Verwendung 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 { 
    } 
} 

Aber das funktioniert nicht, weil make nicht zurückgibt der richtige Typ für Unterklassen. (Das Problem ist also new SolParent();).

Was ist der beste Weg, dies zu lösen? Ich brauche alle Unterklassen zur Ausführung showFields, aber ich kann nicht darauf verlassen, dass sie es explizit tun.

+0

In Ihrem zweiten Beispiel, warum eine 'make' Methode implementieren? Warum nicht einfach 'new SolChild(). ShowFields();' – ToYonos

+3

Rufen Sie solche Methoden nicht von einem Konstruktor. Sie tragen nicht zur Initialisierung bei und gehören daher nicht in Konstruktoren. –

+0

@ToYonos Weil dann Leute, die meine Klasse benutzen, vielleicht vergessen, das zu tun – Mark

Antwort

2

Ihre Showfields-Methode muss die Klassenhierarchie, so etwas zu durchqueren:

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(); 
    } 
} 

Bitte beachte, dass ich Class.getDeclaredFields() verwendet, nicht Class.getFields(), da letztere nur öffentliche Felder verarbeitet.


Und das ist, wie Sie Ihre Klassen in allgemeiner Weise zu konstruieren:

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; 
} 

Beachten Sie, dass dies nur funktioniert, wenn Ihr Subtyp von SolParent einen öffentlichen hat keinen-args Konstruktor (oder kein Konstruktor überhaupt).

+2

'make' wird immer noch eine Instanz des Elterns erstellen, nicht das Kind. – assylias

+1

@assylias guter Punkt.Instanziierungscode hinzugefügt –

+0

Während das Sinn macht, glaube ich nicht, dass das das Problem ist. Die Attribute der Eltern sind bereits gefunden, Kinder sind noch nicht initialisiert. EDIT: über Ihre Bearbeitung, ich bin mir nicht sicher, was "Klasse Typ" ist, werde ich in das und wieder kommen – Mark