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

ben*_*zen 107 java reflection inheritance private-members

我找到了一种方法来获取继承成员通过 class.getDeclaredFields(); 和访问私人成员,class.getFields() 但我正在寻找私人继承的字段.我怎样才能实现这一目标?

aio*_*obe 126

这应该演示如何解决它:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

5
Run Code Online (Sandbox Code Playgroud)


Sea*_*oyd 44

这里最好的方法是使用访问者模式查找类和所有超类中的所有字段并对它们执行回调操作.


履行

Spring有一个很好的Utility类ReflectionUtils就是这样做的:它定义了一个循环遍历所有超类的所有字段并使用回调的方法:ReflectionUtils.doWithFields()

文档:

在目标类的所有字段上调用给定的回调,向上运行类层次结构以获取所有声明的字段.

参数:
- clazz - 要分析的目标类
- fc - 为每个字段调用的回调
- ff - 确定要将回调应用于的字段的过滤器

示例代码:

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);
        }
    });
Run Code Online (Sandbox Code Playgroud)

输出:

在类javax.management.relation.RoleUnresolvedList中
找到字段private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe找到字段private transient boolean javax.management.relation.RoleUnresolvedList.tainted类型类javax.management.relation.RoleUnresolvedList
Found字段private transient java.lang.Object [] java.util.ArrayList.elementData in type class java.util.ArrayList
Found field private int java.util.ArrayList.size in type class java.util.ArrayList
Found field protected transient int java.类java.util.AbstractList中的util.AbstractList.modCount

  • 这不是一个"访问者模式",但如果你的代码中有Spring病毒,它仍然是一个非常好的工具.谢谢分享:) (3认同)
  • @ jose.diego我很确定你可以争论这件事.它访问类层次结构而不是对象树,但原则保持不变 (2认同)

jqn*_*qno 34

这样做:

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;
}
Run Code Online (Sandbox Code Playgroud)

如果你使用像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;
}
Run Code Online (Sandbox Code Playgroud)


Ext*_*r13 19

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);
}
Run Code Online (Sandbox Code Playgroud)

(基于这个答案)


ben*_*zen 15

事实上,我使用复杂类型的层次结构,因此您的解决方案并不完整.我需要进行递归调用以获取所有私有继承的字段.这是我的解决方案

 /**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

  • Vector有很大的开销,因为一切都是同步的.在需要同步的地方,java.util.concurrent中有更好的类.在大多数情况下,Vector,Hashtable和StringBuffer应该由ArrayList,HashMap和StringBuilder替换 (7认同)

mgu*_*mon 8

我需要在Model Citizen中为蓝图添加对继承字段的支持.我派生的这个方法更简洁,可以检索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;
}
Run Code Online (Sandbox Code Playgroud)


Ken*_*son 7

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);
}
Run Code Online (Sandbox Code Playgroud)