Вопрос по private-members, java, inheritance, reflection – Доступ к частным унаследованным полям через отражение в Java

102

Я нашел способ получить унаследованных членов черезclass.getDeclaredFields(); и доступ к частным членам черезclass.getFields() Но я ищу частные унаследованные поля. Как я могу достичь этого?

При этом защищенные поля наследуются, но вы должны сделать то же самое, чтобы получить их с помощью отражения. Bozho
«частные унаследованные поля» не существует. Если поле является закрытым, оно не наследуется и остается только в области действия родительского класса. Чтобы получить доступ к родительским частным полям, вы должны сначала получить доступ к родительскому классу (см. Ответ aioobe) Benoit Courtine

Ваш Ответ

7   ответов
40

Шаблон посетителя найти все поля в классе и всех суперклассах и выполнить с ними действие обратного вызова.

Реализация

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.typeSafe в классе типов javax.management.relation.RoleUnresolvedList
Найдено поле частного временного логического объекта javax.management.relation.RoleUnresolvedList.tainted в классе типа javax.management.relation.RoleUnresolvedList
Обнаружено поле частного переходного процесса java.lang.Object [] java.util.ArrayList.elementData в классе типов java.util.ArrayList
Найдено поле private int java.util.ArrayList.size в классе типов java.util.ArrayList
Обнаружено поле защищенного переходного процесса int java.util.AbstractList.modCount в классе типов java.util.AbstractList

@ jose.diego Я уверен, что вы могли бы поспорить об этом. Он посещает иерархию классов, а не дерево объектов, но принцип остается тем же Sean Patrick Floyd
Очень плохо, что JavaDoc для этого класса указывает, что «он предназначен только для внутреннего использования», так что это представляет собой возможный риск для любого, кто желает его использовать. spaceman spiff
это не «шаблон посетителя», но он все же очень хороший инструмент, если в вашем коде есть вирус Spring. спасибо что поделились :) thinlizzy
Не уверен, что этот комментарий получит ответ, но вы только посещаете определенное поле одновременно с этим решением. Если мне нужно одновременно посмотреть на другие поля - например, установить для этого поля значение «abc», если другое поле равно NULL, - у меня нет объекта в целом, доступного для меня. gene b.
@spacemanspiff вы технически правы, но этот класс существует уже около 15 лет (включая 4 основные версии выпуска) и широко используется многими клиентами Spring. Я сомневаюсь, что они вернут это сейчас. Sean Patrick Floyd
31

Это сделаем это:

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;
}
Одна небольшая проблема с Java. Вы не можете сделать addAll (Field []), вам нужно изменить его на addAll (Arrays.asList (i.getDeclaredFields ())); gene b.
Спасибо за превосходный ответ ~ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼
решено давно - он обновил ответ gene b.
это получает объявленные и унаследованные поля класса аргумента, поэтому должно называться getDeclaredAndInheritedPrivateFields. идеально, хотя спасибо! Peter Hawkins
17
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);
}

(на основеэтот ответ)

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);
}
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;
}
хорошо, я был неправ, спасибо за указание мне эту ссылку. benzen
Вектор плохой старый код. Пожалуйста, используйте текущую структуру данных из каркаса коллекций (в большинстве случаев достаточно ArrayList) Sean Patrick Floyd
«Что касается платформы Java 2 v1.2, этот класс был модифицирован для реализации List, так что он стал частью инфраструктуры сбора Java». дооснащен в 1.2? если это не старый, то что? Источник:download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html Sean Patrick Floyd
Вектор имеет огромные накладные расходы, потому что все синхронизировано. А там, где вам нужна синхронизация, в java.util.concurrent есть лучшие классы. Vector, Hashtable и StringBuffer в большинстве случаев должны быть заменены на ArrayList, HashMap и StringBuilder Sean Patrick Floyd
7

Мне нужно было добавить поддержку унаследованных полей для чертежей вМодель Гражданин, Я получил этот метод, который является более кратким для получения полей класса + унаследованных полей.

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

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
Получает ли это все поля суперклассов или только прямой суперкласс? s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼
Прямые поля суперклассов. Вы можете записаться наgetSuperclass() пока не достигнешьnull если хочешь пойти выше. aioobe
getDeclaredFields() для того, кого я искал. Спасибо shkschneider

Похожие вопросы