Znalazłem sposób na zdobycie dziedziczonych członków przez class.getDeclaredFields();
i dostęp do prywatnych członków przez class.getFields()
Ale ja szukam prywatnych dziedziczonych pól. Jak mogę to osiągnąć?
Znalazłem sposób na zdobycie dziedziczonych członków przez class.getDeclaredFields();
i dostęp do prywatnych członków przez class.getFields()
Ale ja szukam prywatnych dziedziczonych pól. Jak mogę to osiągnąć?
Odpowiedzi:
Powinno to pokazać, jak go rozwiązać:
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));
}
}
(Lub Class.getDeclaredFields
dla tablicy wszystkich pól.)
Wynik:
5
getSuperclass()
aż osiągniesz, null
jeśli chcesz iść wyżej.
getDeclaredFields()[0]
lub getDeclaredField("i")
raczej powtarzasz [0]
dostęp do tablicy w następnych dwóch instrukcjach?
getDeclaredFields
. Odpowiedź została zaktualizowana.
Najlepszym podejściem w tym przypadku jest użycie wzorca gościa, aby znaleźć wszystkie pola w klasie i wszystkie superklasy i wykonać na nich akcję zwrotną.
Spring ma ładną klasę Utility ReflectionUtils
, która właśnie to robi: definiuje metodę pętli po wszystkich polach wszystkich superklas z wywołaniem zwrotnym:ReflectionUtils.doWithFields()
Wywołaj podane wywołanie zwrotne we wszystkich polach w klasie docelowej, przechodząc w górę hierarchii klas w celu pobrania wszystkich zadeklarowanych pól.
Parametry:
- clazz - klasa docelowa do analizy
- fc - wywołanie zwrotne do wywołania dla każdego pola
- ff - filtr określający pola do zastosowania wywołania zwrotnego
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);
}
});
Znaleziono pola prywatne przemijający logiczna javax.management.relation.RoleUnresolvedList.typeSafe w klasie typu javax.management.relation.RoleUnresolvedList
znaleźć pole prywatny przejściowy logiczna javax.management.relation.RoleUnresolvedList.tainted w klasie typu javax.management.relation.RoleUnresolvedList
Znalezione dziedzinie private przejściowy java.lang.Object [] java.util.ArrayList.elementData w klasie typu java.util.ArrayList
Znalezione pole prywatne int java.util.ArrayList.size w klasie typu java.util.ArrayList
Znalezione pole chronione przejściowo int java. util.AbstractList.modCount w klasie typu java.util.AbstractList
To wystarczy:
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;
}
Jeśli używasz narzędzia do pokrycia kodu, takiego jak EclEmma , musisz uważać: dodają one ukryte pole do każdej z twoich klas. W przypadku EclEmma te pola są oznaczone jako syntetyczne i możesz je odfiltrować w następujący sposób:
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);
}
(na podstawie tej odpowiedzi)
W rzeczywistości używam złożonej hierarchii typów, więc rozwiązanie nie jest kompletne. Muszę wykonać wywołanie rekurencyjne, aby pobrać wszystkie prywatne pola dziedziczone. Oto moje rozwiązanie
/**
* 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;
}
Musiałem dodać obsługę dziedziczonych pól dla planów w Model Citizen . Wyprowadziłem tę metodę, która jest nieco bardziej zwięzła do pobierania pól klasy + dziedziczonych pól.
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);
}