在Java中通过reflection访问私有inheritance的字段

我发现了一种通过class.getDeclaredFields();获得inheritance成员的方法class.getDeclaredFields(); 并访问私人成员通过class.getFields()但我在寻找私人inheritance领域。 我怎么能做到这一点?

这应该演示如何解决它:

 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[] fs = b.getClass().getSuperclass().getDeclaredFields(); fs[0].setAccessible(true); System.out.println(fs[0].get(b)); } } 

输出:

 5 

这里最好的方法是使用访问者模式 ,find类和所有超类的所有字段,并对它们执行callback操作。


履行

Spring有一个不错的Utility类ReflectionUtils ,它只是这样做的:它定义了一个方法来循环遍历所有超类的所有字段: ReflectionUtils.doWithFields()

文档:

在目标类中的所有字段上调用给定的callback函数,向上类层次结构以获取所有声明的字段。

参数:
– clazz – 要分析的目标课程
– fc – 为每个字段调用的callback
– ff – 确定应用callback的字段的filter

示例代码:

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

输出:

发现字段私有临时布尔型javax.management.relation.RoleUnresolvedList中的javax.management.relation.RoleUnresolvedList.typeSafe类
发现字段私有临时布尔型javax.management.relation.RoleUnresolvedList中的javax.management.relation.RoleUnresolvedList.tainted类
find字段private transient java.lang.Object []类java.util.ArrayList中的java.util.ArrayList.elementData
find字段types为java.util.ArrayList的类java.util.ArrayList.size中的字段
发现字段保护瞬态int类java.util.AbstractList类中的java.util.AbstractList.modCount

这将做到这一点:

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

如果使用EclEmma之类的代码覆盖工具,则必须注意:他们为每个类添加一个隐藏字段。 在EclEmma的情况下,这些字段被标记为合成的 ,你可以像这样过滤掉它们:

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

事实上,我使用一个复杂的types层次,所以你的解决scheme是不完整的。 我需要做一个recursion调用来获得所有的私有inheritance领域。 这是我的解决scheme

  /** * 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; } 
 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); } 

(根据这个答案)

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

我需要在Model Citizen中添加对蓝图的inheritance字段的支持。 我推导出这个方法更简洁,用于检索一个类的字段+inheritance的字段。

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