В чем разница между getFields и getDeclaredFields в отражении Java?
Я немного смущен различием метода getFields
и метода getDeclaredFields
при использовании отражения Java.
Я читал, что getDeclaredFields
дает вам доступ ко всем полям класса и что getFields
возвращает только публичные поля. Если это так, почему бы вам просто не использовать getDeclaredFields
?
Может кто-то прокомментировать это и объяснить разницу между этими двумя методами, и когда/почему вы хотели бы использовать один над другим?
Ответы
Ответ 1
GetFields()
Все public
поля по всей иерархии классов.
getDeclaredFields()
Все поля, независимо от их доступности, но только для текущего класса, а не базовые классы, от которых может наследоваться текущий класс.
Чтобы получить все поля в иерархии, я написал следующую функцию:
public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass,
@Nullable Class<?> exclusiveParent) {
List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
Class<?> parentClass = startClass.getSuperclass();
if (parentClass != null &&
(exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
List<Field> parentClassFields =
(List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
currentClassFields.addAll(parentClassFields);
}
return currentClassFields;
}
Класс exclusiveParent
предназначен для предотвращения извлечения полей из Object
. Это может быть null
если вы действительно хотите поля Object
.
Чтобы уточнить, Lists.newArrayList
происходит из Lists.newArrayList
.
Обновить
К вашему сведению, приведенный выше код опубликован на GitHub в моем проекте LibEx в ReflectionUtils.
Ответ 2
Как уже упоминалось, Class.getDeclaredField(String)
рассматривает только поля из Class
, в которых вы его называете.
Если вы хотите найти a Field
в иерархии Class
, вы можете использовать эту простую функцию:
/**
* Returns the first {@link Field} in the hierarchy for the specified name
*/
public static Field getField(Class<?> clazz, String name) {
Field field = null;
while (clazz != null && field == null) {
try {
field = clazz.getDeclaredField(name);
} catch (Exception e) {
}
clazz = clazz.getSuperclass();
}
return field;
}
Это полезно, например, найти поле private
из суперкласса. Кроме того, если вы хотите изменить его значение, вы можете использовать его следующим образом:
/**
* Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name
*/
public static void setField(Object object, String fieldName, Object value) throws Exception {
Field field = getField(object.getClass(), fieldName);
field.setAccessible(true);
field.set(object, value);
}
Ответ 3
public Field[] getFields() throws SecurityException
Возвращает массив, содержащий объекты Field, отражающие все доступные общедоступные поля класса или интерфейса, представленные этим объектом класса. Элементы возвращаемого массива не сортируются и не находятся в каком-либо определенном порядке. Этот метод возвращает массив длины 0, если класс или интерфейс не имеет доступных общедоступных полей или если он представляет класс массива, примитивный тип или void.
В частности, если этот объект класса представляет класс, этот метод возвращает общедоступные поля этого класса и всех его суперклассов. Если этот объект класса представляет собой интерфейс, этот метод возвращает поля этого интерфейса и всех его суперинтерфейсов.
Неявное поле длины для класса массива не отражается этим методом. Пользовательский код должен использовать методы класса Array для управления массивами.
public Field[] getDeclaredFields() throws SecurityException
Возвращает массив объектов Field, отражающий все поля, объявленные классом или интерфейсом, представленным этим объектом класса. Этот включает общедоступный, защищенный, стандартный (пакетный) доступ и частные поля, но исключает наследуемые поля. Элементы возвращаемого массива не сортируются и не находятся в каком-либо определенном порядке. Этот метод возвращает массив длины 0, если класс или интерфейс не объявляет никаких полей, или если этот объект класса представляет примитивный тип, класс массива или void.
А что, если мне нужны все поля из всех родительских классов?
Некоторый код необходим, например. от fooobar.com/questions/49122/...:
public static List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}
Ответ 4
Из учебников Java Reflection:
![enter image description here]()