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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3567372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 01:55:09  来源:igfitidea点击:

Access to private inherited fields via reflection in Java

javareflectioninheritanceprivate-members

提问by benzen

I found a way to get inherited members via class.getDeclaredFields();and acces to private members via class.getFields()But i'm looking for private inherited fields. How can i achieve this?

我找到了一种方法来获取继承的成员,class.getDeclaredFields();并通过 访问私有成员,class.getFields()但我正在寻找私有的继承字段。我怎样才能做到这一点?

采纳答案by benzen

In fact i use a complex type hierachy so you solution is not complete. I need to make a recursive call to get all the private inherited fields. Here is my solution

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

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

回答by aioobe

This should demonstrate how to solve it:

这应该演示如何解决它:

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

(Or Class.getDeclaredFieldsfor an array of all fields.)

(或者Class.getDeclaredFields对于所有字段的数组。)

Output:

输出:

5

回答by jqno

This'll do it:

这样做:

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 synthetic, and you can filter them out like this:

如果您使用像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;
}

回答by Sean Patrick Floyd

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

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



Implementation

执行

Spring has a nice Utility class ReflectionUtilsthat does just that: it defines a method to loop over all fields of all super classes with a callback: ReflectionUtils.doWithFields()

Spring 有一个很好的 Utility 类ReflectionUtils可以做到这一点:它定义了一个方法来通过回调循环遍历所有超类的所有字段:ReflectionUtils.doWithFields()

Documentation:

文档:

Invoke the given callback on all fields in the target class, going up the class hierarchy to get all declared fields.

Parameters:
- clazz - the target class to analyze
- fc - the callback to invoke for each field
- ff - the filter that determines the fields to apply the callback to

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

参数:
- 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);
        }
    });

Output:

输出:

Found field private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe in type class javax.management.relation.RoleUnresolvedList
Found field private transient boolean javax.management.relation.RoleUnresolvedList.tainted in type class javax.management.relation.RoleUnresolvedList
Found field 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.util.AbstractList.modCount in type class java.util.AbstractList

在类型类 javax.management.relation.RoleUnresolvedList 中
找到字段私有瞬态布尔 javax.management.relation.RoleUnresolvedList.typeSafe 在类型类 javax.management.relation.RoleUnresolvedList中找到字段私有瞬态布尔 javax.management.relation.RoleUnresolvedList.tainted
找到字段私有瞬态 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瞬态 int java。类型类 java.util.AbstractList 中的 util.AbstractList.modCount

回答by Kenny Cason

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

回答by Exterminator13

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

(based on thisanswer)

(基于这个答案)

回答by mguymon

I needed to add support for inherited fields for blueprints in Model Citizen. I derived this method that is a bit more concise for retrieving a Class' fields + inherited fields.

我需要在Model Citizen 中为蓝图添加对继承字段的支持。我派生了这个方法,它更简洁地检索类的字段 + 继承的字段。

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