J'ai trouvé un moyen d'obtenir des membres hérités via class.getDeclaredFields();
et d'accéder aux membres privés via class.getFields()
Mais je recherche des champs hérités privés. Comment puis-je atteindre cet objectif?
J'ai trouvé un moyen d'obtenir des membres hérités via class.getDeclaredFields();
et d'accéder aux membres privés via class.getFields()
Mais je recherche des champs hérités privés. Comment puis-je atteindre cet objectif?
Réponses:
Cela devrait montrer comment le résoudre:
import java.lang.reflect.Field;
class Super {
private int i = 5;
}
public class B extends Super {
public static void main(String[] args) throws Exception {
B b = new B();
Field f = b.getClass().getSuperclass().getDeclaredField("i");
f.setAccessible(true);
System.out.println(f.get(b));
}
}
(Ou Class.getDeclaredFields
pour un tableau de tous les champs.)
Production:
5
getSuperclass()
jusqu'à ce que vous atteigniez null
si vous voulez aller plus haut.
getDeclaredFields()[0]
ou ne getDeclaredField("i")
répétez-vous pas l' [0]
accès au tableau dans les deux instructions suivantes?
getDeclaredFields
. La réponse a été mise à jour.
La meilleure approche ici consiste à utiliser le modèle de visiteur pour trouver tous les champs de la classe et toutes les super classes et exécuter une action de rappel sur eux.
Spring a une belle classe Utility ReflectionUtils
qui fait exactement cela: il définit une méthode pour boucler sur tous les champs de toutes les super classes avec un rappel:ReflectionUtils.doWithFields()
Appelez le rappel donné sur tous les champs de la classe cible, en remontant la hiérarchie des classes pour obtenir tous les champs déclarés.
Paramètres:
- clazz - la classe cible à analyser
- fc - le callback à invoquer pour chaque champ
- ff - le filtre qui détermine les champs auxquels appliquer le callback
ReflectionUtils.doWithFields(RoleUnresolvedList.class,
new FieldCallback(){
@Override
public void doWith(final Field field) throws IllegalArgumentException,
IllegalAccessException{
System.out.println("Found field " + field + " in type "
+ field.getDeclaringClass());
}
},
new FieldFilter(){
@Override
public boolean matches(final Field field){
final int modifiers = field.getModifiers();
// no static fields please
return !Modifier.isStatic(modifiers);
}
});
Champ privé transitoire booléen javax.management.relation.RoleUnresolvedList.typeSafe
trouvé dans la classe de type javax.management.relation.RoleUnresolvedList Champ trouvé privé transitoire booléen javax.management.relation.RoleUnresolvedList.tainted dans la classe de type javax.management.relationList.Role
champ Foundresolved private transient java.lang.Object [] java.util.ArrayList.elementData dans la classe de type java.util.ArrayList
Champ trouvé private int java.util.ArrayList.size dans la classe de type java.util.ArrayList
Trouvé champ protected transient int java. util.AbstractList.modCount dans la classe de type java.util.AbstractList
Cela va le faire:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
Collections.addAll(result, i.getDeclaredFields());
i = i.getSuperclass();
}
return result;
}
Si vous utilisez un outil de couverture de code comme EclEmma , vous devez faire attention: ils ajoutent un champ caché à chacune de vos classes. Dans le cas d'EclEmma, ces champs sont marqués comme synthétiques et vous pouvez les filtrer comme ceci:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
for (Field field : i.getDeclaredFields()) {
if (!field.isSynthetic()) {
result.add(field);
}
}
i = i.getSuperclass();
}
return result;
}
public static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
try {
Field f = tmpClass.getDeclaredField(fieldName);
return f;
} catch (NoSuchFieldException e) {
tmpClass = tmpClass.getSuperclass();
}
} while (tmpClass != null);
throw new RuntimeException("Field '" + fieldName
+ "' not found on class " + clazz);
}
(basé sur cette réponse)
En fait, j'utilise une hiérarchie de type complexe afin que votre solution ne soit pas complète. J'ai besoin de faire un appel récursif pour obtenir tous les champs hérités privés. Voici ma solution
/**
* Return the set of fields declared at all level of class hierachy
*/
public Vector<Field> getAllFields(Class clazz) {
return getAllFieldsRec(clazz, new Vector<Field>());
}
private Vector<Field> getAllFieldsRec(Class clazz, Vector<Field> vector) {
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
getAllFieldsRec(superClazz, vector);
}
vector.addAll(toVector(clazz.getDeclaredFields()));
return vector;
}
J'avais besoin d'ajouter la prise en charge des champs hérités pour les plans dans Model Citizen . J'ai dérivé cette méthode qui est un peu plus concise pour récupérer les champs d'une classe + les champs hérités.
private List<Field> getAllFields(Class clazz) {
List<Field> fields = new ArrayList<Field>();
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
fields.addAll(getAllFields(superClazz));
}
return fields;
}
private static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
for ( Field field : tmpClass.getDeclaredFields() ) {
String candidateName = field.getName();
if ( ! candidateName.equals(fieldName) ) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while ( clazz != null );
throw new RuntimeException("Field '" + fieldName +
"' not found on class " + clazz);
}