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

发布于 2024-09-15 19:28:34 字数 108 浏览 7 评论 0原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

美人如玉 2024-09-22 19:28:34

这应该演示如何解决它:(

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

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.getDeclaredFields for an array of all fields.)

Output:

5
淡笑忘祈一世凡恋 2024-09-22 19:28:34

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


Spring有一个很好的实用

程序类 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);
        }
    });

输出:

在类型类 javax.management.relation.RoleUnresolvedList 中找到字段私有瞬态布尔 javax.management.relation.RoleUnresolvedList.typeSafe
在类型类 javax.management.relation.RoleUnresolvedList 中找到字段私有瞬态布尔 javax.management.relation.RoleUnresolvedList.tainted
在类型类 java.util.ArrayList
中找到字段私有瞬态 java.lang.Object[] java.util.ArrayList.elementData
在类型类 java.util.ArrayList 中找到字段 private int java.util.ArrayList.size
在类型类 java.util.AbstractList 中找到字段 protected瞬态 int java.util.AbstractList.modCount

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.


Implementation

Spring has a nice Utility class ReflectionUtils that does just that: it defines a method to loop over all fields of all super classes with a callback: 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

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

无语# 2024-09-22 19:28: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;
}

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

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:

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;
}
執念 2024-09-22 19:28:34
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);
}

(基于这个答案)

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 this answer)

余生一个溪 2024-09-22 19:28:34

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

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

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 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;
}
初吻给了烟 2024-09-22 19:28:34
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);
}
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);
}
红墙和绿瓦 2024-09-22 19:28:34

我需要在 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;
}

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.

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;
}
筑梦 2024-09-22 19:28:34

Commons Lang 有 util 方法 FieldUtils#getAllFieldsList 为此。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文