通过 Java 中的反射访问私有继承字段

我找到了通过 class.getDeclaredFields();获得继承成员的方法 以及通过 class.getFields()接触私人会员 But i'm looking for private inherited fields. How can i achieve this?

100607 次浏览

这应该说明如何解决这个问题:

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

(或者 Class.getDeclaredFields表示所有字段的数组。)

产出:

5

事实上,我使用一个复杂的类型层次结构,所以你的解决方案是不完整的。 我需要进行一个递归调用来获取所有私有继承字段。 这是我的解决办法

 /**
* Return the set of fields declared at all level of class hierachy
*/
public static List<Field> getAllFields(Class<?> clazz) {
return getAllFieldsRec(clazz, new ArrayList<>());
}


private static List<Field> getAllFieldsRec(Class<?> clazz, List<Field> list) {
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null) {
getAllFieldsRec(superClazz, list);
}
list.addAll(Arrays.asList(clazz.getDeclaredFields()));
return list;
}

这个可以:

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

If you use a code coverage tool like EclEmma, you have to watch out: they add a hidden field to each of your classes. In the case of EclEmma, these fields are marked 合成的, and you can filter them out like this:

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

The best approach here is using the Visitor Pattern do find all fields in the class and all super classes and execute a callback action on them.


实施

Spring 有一个很好的 Utilityclass ReflectionUtils,它就是这么做的: 它定义了一个方法,用一个回调函数 ReflectionUtils.doWithFields()遍历所有超类的所有字段

文件:

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

Parameters:
- clazz-要分析的目标类
- fc-每个字段调用的回调
- ff-确定要应用回调的字段的筛选器

Sample code:

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 ement.relations. RoleUnResolvedList.typeSafe 在类型 javax.management ement.relations. RoleUnResolvedList 中
找到字段私有的瞬态布尔值 javax.management. relations. RoleUnResolvedList.protected 在类型 javax.management. relations. RoleUnResolvedList 中
在 java.util.ArrayList 类型中找到字段私有瞬态 java.lang. Object [] java.util.ArrayList.elementData
在类 java.util. ArrayList 中找到字段 private int java.util. ArrayList.size
Found field protected transient int java.util.AbstractList.modCount in type class java.util.AbstractList

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

(根据 这个答案)

我需要在 模范市民中添加对蓝图继承字段的支持。我派生了这个方法,它对于检索 Class 的字段 + 继承字段来说更简洁一些。

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

Commons Lang has the util method FieldUtils#getAllFieldsList for this.