2017-03-14 1 views
0

Je n'arrive pas à faire fonctionner la réflexion dans un constructeur de classe avec l'héritage. Plus précisément, j'aimerais obtenir toutes les valeurs d'attribut.Réflexion dans le constructeur avec héritage (Java)

Voici une démo pour la mise en œuvre naïve qui ne fonctionne pas:

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

Cela montrera que childVar est égal à zéro:

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

Parce qu'il est pas encore initialisé.

donc je suppose que je vais avoir besoin de ne pas utiliser le constructeur directement, mais plutôt laisser le constructeur complet et puis utilisation 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 { 
    } 
} 

Mais cela ne fonctionne pas parce que make ne retourne pas le type correct pour les sous-classes. (Donc le problème est new SolParent();).

Quelle est la meilleure façon de résoudre ce problème? J'ai besoin de toutes les sous-classes pour exécuter showFields, mais je ne peux pas compter sur les faire explicitement.

+0

Dans votre deuxième exemple, pourquoi implémenter une méthode 'make'? Pourquoi ne pas faire juste 'new SolChild(). ShowFields();' – ToYonos

+3

N'appelez pas de telles méthodes d'un constructeur. Ils ne contribuent pas à l'initialisation et n'appartiennent donc pas aux constructeurs. –

+0

@ToYonos Parce que les gens qui utilisent ma classe pourraient alors oublier de le faire – Mark

Répondre

2

Votre méthode showFields doit parcourir la hiérarchie des classes, quelque chose comme ceci:

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

Notez que je Class.getDeclaredFields(), pas Class.getFields(), car ces derniers ne traite que les domaines publics.


Et voici comment vous pouvez construire vos classes de façon générique:

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

Notez que cela ne fonctionnera que si votre sous-type de SolParent a un constructeur public no-args (ou pas de constructeur du tout).

+2

'make' créera toujours une instance du parent, pas l'enfant. – assylias

+1

@assylias bon point.code d'instanciation ajouté –

+0

Bien que cela ait du sens, je ne pense pas que ce soit le problème. Les attributs sur les parents sont déjà trouvés, les enfants ne sont pas encore initialisés. EDIT: à propos de votre édition, je ne suis pas sûr de ce qu'est 'Class type' est, je vais regarder dans et revenir – Mark