Ich habe einen Weg gefunden, geerbte Mitglieder über zu erhalten class.getDeclaredFields();
und auf private Mitglieder über zuzugreifen. class.getFields()
Aber ich suche nach privaten geerbten Feldern. Wie kann ich das erreichen?
Ich habe einen Weg gefunden, geerbte Mitglieder über zu erhalten class.getDeclaredFields();
und auf private Mitglieder über zuzugreifen. class.getFields()
Aber ich suche nach privaten geerbten Feldern. Wie kann ich das erreichen?
Antworten:
Dies sollte zeigen, wie es gelöst werden kann:
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));
}
}
(Oder Class.getDeclaredFields
für ein Array aller Felder.)
Ausgabe:
5
getSuperclass()
bis Sie erreichen, null
wenn Sie höher gehen möchten.
getDeclaredFields()[0]
oder getDeclaredField("i")
wiederholen Sie den [0]
Array-Zugriff nicht in den nächsten beiden Anweisungen?
getDeclaredFields
. Die Antwort wurde aktualisiert.
Der beste Ansatz hier ist die Verwendung des Besuchermusters. Finden Sie alle Felder in der Klasse und alle Superklassen und führen Sie eine Rückrufaktion für sie aus.
Spring hat eine nette Utility-Klasse ReflectionUtils
, die genau das tut: Sie definiert eine Methode, um alle Felder aller Superklassen mit einem Rückruf zu durchlaufen:ReflectionUtils.doWithFields()
Rufen Sie den angegebenen Rückruf für alle Felder in der Zielklasse auf und gehen Sie die Klassenhierarchie nach oben, um alle deklarierten Felder abzurufen.
Parameter:
- clazz - die zu analysierende Zielklasse -
fc - der für jedes Feld aufzurufende Rückruf
- ff - der Filter, der die Felder bestimmt, auf die der Rückruf angewendet werden soll
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);
}
});
Gefunden Feld Private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe in Typklasse javax.management.relation.RoleUnresolvedList
gefunden Feld Private transiente boolean javax.management.relation.RoleUnresolvedList.tainted in Typklasse javax.management.relation.RoleUnresolvedList
gefunden Feld private transient java.lang.Object [] java.util.ArrayList.elementData in der Typklasse java.util.ArrayList
Gefundenes Feld private int java.util.ArrayList.size in der Typklasse java.util.ArrayList
Gefundenes Feld geschützt transient int java. util.AbstractList.modCount in der Typklasse java.util.AbstractList
Das wird es tun:
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;
}
Wenn Sie ein Tool zur Codeabdeckung wie EclEmma verwenden , müssen Sie darauf achten , dass jeder Ihrer Klassen ein verstecktes Feld hinzugefügt wird. Im Fall von EclEmma sind diese Felder als synthetisch markiert , und Sie können sie wie folgt herausfiltern:
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);
}
(basierend auf dieser Antwort)
Tatsächlich verwende ich eine komplexe Hierarchie, so dass Ihre Lösung nicht vollständig ist. Ich muss einen rekursiven Aufruf durchführen, um alle privaten geerbten Felder abzurufen. Hier ist meine Lösung
/**
* 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;
}
Ich musste Unterstützung für geerbte Felder für Blaupausen in Model Citizen hinzufügen . Ich habe diese Methode abgeleitet, die etwas präziser ist, um Felder + geerbte Felder einer Klasse abzurufen.
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);
}