Je fais un projet universitaire.
Je dois obtenir tous les champs de la classe. Même privé et hérité. J'ai essayé d'obtenir tous les champs déclarés, puis de lancer en super classe et de répéter. Fragment de mon code:
private void listAllFields(Object obj) {
List<Field> fieldList = new ArrayList<Field>();
while (obj != null) {
fieldList.addAll(Arrays.asList(obj.getClass().getDeclaredFields()));
obj = obj.getClass().getSuperclass().cast(obj);
}
// rest of code
Mais ça ne marche pas. tmpObj
après la conversion est toujours la même classe (pas la superclasse).
J'apprécierai toute aide pour résoudre un problème de casting ou pour récupérer ces champs de manière différente.
Le problème n'est pas d'accéder aux champs, mais d'obtenir les noms des champs!
Je le gère comme suit:
private void listAllFields(Object obj) {
List<Field> fieldList = new ArrayList<Field>();
Class tmpClass = obj.getClass();
while (tmpClass != null) {
fieldList.addAll(Arrays.asList(tmpClass .getDeclaredFields()));
tmpClass = tmpClass .getSuperclass();
}
// rest of code
obj = obj.getClass().getSuperclass().cast(obj);
Cette ligne ne fait pas ce que vous attendez d'elle. Lancer un Object
ne le change pas, il indique simplement au compilateur de le traiter comme autre chose.
Par exemple. vous pouvez convertir un List
en un Collection
, mais il restera toujours un List
.
Cependant, boucler à travers les super-classes pour accéder aux champs fonctionne bien sans transtypage:
Class<?> current = yourClass;
while(current.getSuperclass()!=null){ // we don't want to process Object.class
// do something with current's fields
current = current.getSuperclass();
}
En passant, si vous avez accès au framework Spring, il existe une méthode pratique pour parcourir en boucle les champs d'une classe et de toutes les super classes:ReflectionUtils.doWithFields(baseClass, FieldCallback)
(voir aussi ma réponse précédente: Accès aux champs hérités privés via une réflexion en Java )
getDeclaredFields()
vous donne tous les champs de cette classe, y compris ceux de private
.
getFields()
vous donne tous les champs public
de cette classe ET ses super-classes.
Si vous voulez private
/protected
méthodes de super classes, vous devrez appeler à plusieurs reprises getSuperclass()
puis appelez getDeclaredFields()
sur l'objet Super Class.
Rien ici n’est clairement expliqué dans le javadocs
Voici la méthode que j'utilise pour obtenir tous les champs d'un objet
private <T> List<Field> getFields(T t) {
List<Field> fields = new ArrayList<>();
Class clazz = t.getClass();
while (clazz != Object.class) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
return fields;
}
essayez ces
Comment lire un champ privé en Java?
Est-il possible dans Java d'accéder aux champs privés via réflexion
Field.setAccessible (true) est ce que vous devez faire pour le rendre accessible par réflexion.
import Java.lang.reflect.Field;
class B
{
private int i = 5;
}
public class A extends B
{
public static void main(String[] args) throws Exception
{
A a = new A();
Field[] fs = a.getClass().getSuperclass().getDeclaredFields();
for (Field field : fs)
{
field.setAccessible(true);
System.out.println( field.get( a ) );
}
}
}
ClassName obj = new ClassName();
Field field = ClassName.class.getDeclaredField ("name of the field");
field.setAccessible (true);
DataType value = (DataType) field.get (obj);
Vous devez utiliser setAccessible à true avant d'extraire la valeur. Parfois, la machine virtuelle Java ne permet pas d’extraire la variable privée, elle peut donner une exception de sécurité.
Auparavant demandé.
Accès aux champs hérités privés via une réflexion en Java
Dans votre code, définissez field.setAccessible(true);
Pour obtenir des champs de superclasse, utilisez getSuperclass()
. De là, vous pouvez obtenir des champs de superclasse.
Cette solution utilise des flux Java 8, utiles pour ceux qui apprennent la programmation fonctionnelle en Java. Elle effectue une itération sur getSuperclass et getDeclaredFields comme indiqué dans les autres réponses, mais de manière fonctionnelle.
La ligne suivante affichera le nom de chaque nom de champ trouvé sur SomeClass ou l’une de ses superclasses.
allFieldsFor(SomeClass.class).map(Field::getName).forEach(System.out::println);
Voici le code qui parcourt les superclasses pour créer le flux de champs.
private Stream<Field> allFieldsFor( Class c ) {
return walkInheritanceTreeFor(c).flatMap( k -> Arrays.stream(k.getDeclaredFields()) );
}
private Stream<Class> walkInheritanceTreeFor( Class c ) {
return iterate( c, k -> Optional.ofNullable(k.getSuperclass()) );
}
La méthode suivante est modélisée à partir de Streams.iterate. Cependant, Streams.iterate est conçu pour créer des flux infinis. Cette version a été modifiée pour se terminer lorsque Optional.none () est renvoyé par fetchNextFunction.
private <T> Stream<T> iterate( T seed, Function<T,Optional<T>> fetchNextFunction ) {
Objects.requireNonNull(fetchNextFunction);
Iterator<T> iterator = new Iterator<T>() {
private Optional<T> t = Optional.ofNullable(seed);
public boolean hasNext() {
return t.isPresent();
}
public T next() {
T v = t.get();
t = fetchNextFunction.apply(v);
return v;
}
};
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE),
false
);
}
Oui, il est possible d’utiliser Reflection.
Dans votre code, définissez Field.setAccessible(true);
Allez-y et apprenez le concept mais NE LE FAITES PAS :-)