web-dev-qa-db-fra.com

Quelle est la différence entre getFields et getDeclaredFields dans Java reflet

Je suis un peu confus quant à la différence entre la méthode getFields et la méthode getDeclaredFields lorsque vous utilisez Java reflet.

J'ai lu que getDeclaredFields vous donne accès à tous les champs de la classe et que getFields ne renvoie que des champs publics. Si tel est le cas, pourquoi ne pas simplement utiliser getDeclaredFields?

Quelqu'un peut-il développer cette idée et expliquer la différence entre les deux méthodes, et quand/pourquoi voudriez-vous utiliser l'une plutôt que l'autre?

165
BlackHatSamurai

getFields ()

Tous les public champs de la hiérarchie de classe entière.

getDeclaredFields ()

Tous les champs, quelle que soit leur accessibilité, mais uniquement pour la classe actuelle, pas les classes de base dont la classe actuelle pourrait hériter.

Pour obtenir tous les champs dans la hiérarchie, j'ai écrit la fonction suivante:

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

La classe exclusiveParent permet d'empêcher l'extraction des champs de Object. Ce peut être null si vous voulez les champs Object.

Pour clarifier, Lists.newArrayList vient de Guava.

Mise à jour

Pour votre information, le code ci-dessus est publié sur GitHub dans mon LibEx projet dans ReflectionUtils .

228
John B

Comme déjà mentionné, Class.getDeclaredField(String) ne regarde que les champs de la Class dans laquelle vous l'appelez.

Si vous souhaitez rechercher un Field dans la hiérarchie Class, vous pouvez utiliser cette fonction simple:

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

Ceci est utile pour trouver un champ private d'une super-classe, par exemple. En outre, si vous souhaitez modifier sa valeur, vous pouvez l'utiliser comme suit:

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

public Field[] getFields() throws SecurityException

Renvoie un tableau contenant des objets Field reflétant tous les () champs publics accessibles de la classe ou de l'interface représentée par celui-ci. Objet de classe. Les éléments du tableau renvoyé ne sont pas triés et ne sont dans aucun ordre particulier. Cette méthode retourne un tableau de longueur 0 si la classe ou l'interface n'a pas de champs publics accessibles, ou si elle représente une classe de tableau, un type primitif ou void.

Plus précisément, si cet objet Class représente une classe, cette méthode retourne les champs publics de cette classe et de toutes ses superclasses. Si cet objet Class représente une interface, cette méthode renvoie les champs de cette interface et de toutes ses superinterfaces.

Le champ de longueur implicite pour la classe array n'est pas reflété par cette méthode. Le code utilisateur doit utiliser les méthodes de la classe Array pour manipuler des tableaux.


public Field[] getDeclaredFields() throws SecurityException

Retourne un tableau d'objets Field reflétant tous les champs déclarés par la classe ou l'interface représentée par cette classe. objet. Ce inclut les champs public, protégé, par défaut (paquet) et privé , mais exclut les champs hérités . Les éléments du tableau renvoyé ne sont pas triés et ne sont dans aucun ordre particulier. Cette méthode retourne un tableau de longueur 0 si la classe ou l'interface ne déclare aucun champ ou si cet objet Class représente un type primitif, une classe de tableau ou void.


Et si j'ai besoin de tous les champs de toutes les classes parentes? Un peu de code est nécessaire, par exemple. de https://stackoverflow.com/a/35103361/755804 :

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
1
Somnath Musib