Riflessione Java: come ottenere il valore del campo da un object, non conoscendo la sua class

Dì, ho un metodo che restituisce una List personalizzata con alcuni oggetti. Sono restituiti come Object per me. Ho bisogno di ottenere il valore di un certo campo da questi oggetti, ma non conosco la class degli oggetti.

C’è un modo per farlo via Reflecion o in qualche altro modo?

Supponendo un caso semplice, in cui il tuo campo è public :

 List list; // from your method for(Object x : list) { Class clazz = x.getClass(); Field field = clazz.getField("fieldName"); //Note, this can throw an exception if the field doesn't exist. Object fieldValue = field.get(x); } 

Ma questo è abbastanza brutto, e ho tralasciato tutti i tentativi di cattura, e ho fatto una serie di ipotesi (campo pubblico, riflessione disponibile, buon responsabile della sicurezza).

Se puoi cambiare il tuo metodo per restituire una List , diventa molto semplice perché l’iteratore può quindi darti informazioni sul tipo:

 List list; //From your method for(Foo foo:list) { Object fieldValue = foo.fieldName; } 

O se stai consumando un’interfaccia Java 1.4 dove i generici non sono disponibili, ma conosci il tipo di oggetti che dovrebbero essere nella lista …

 List list; for(Object x: list) { if( x instanceof Foo) { Object fieldValue = ((Foo)x).fieldName; } } 

Nessuna riflessione necessaria 🙂

Se sai in quale class si trova il campo, puoi accedervi usando la reflection. Questo esempio (è in Groovy ma le chiamate al metodo sono identiche) ottiene un object Field per la class Foo e ottiene il suo valore per l’object b . Dimostra che non devi preoccuparti dell’esatta class concreta dell’object, ciò che conta è che tu conosca la class su cui si trova il campo e che quella class sia la class concreta o una superclass dell’object.

 groovy:000> class Foo { def stuff = "asdf"} ===> true groovy:000> class Bar extends Foo {} ===> true groovy:000> b = new Bar() ===> [email protected] groovy:000> f = Foo.class.getDeclaredField('stuff') ===> private java.lang.Object Foo.stuff groovy:000> f.getClass() ===> class java.lang.reflect.Field groovy:000> f.setAccessible(true) ===> null groovy:000> f.get(b) ===> asdf 

Raccomando caldamente di usare i generici di Java per specificare quale tipo di object si trova in quell’Elenco, es. List . Se hai Cars e Trucks puoi usare una superclass / interfaccia comune come questa List .

Tuttavia, puoi utilizzare ReflectionUtils di Spring per rendere accessibili i campi, anche se sono privati ​​come nell’esempio eseguibile seguente:

 List list = new ArrayList(); list.add("some value"); list.add(3); for(Object obj : list) { Class clazz = obj.getClass(); Field field = org.springframework.util.ReflectionUtils.findField(clazz, "value"); org.springframework.util.ReflectionUtils.makeAccessible(field); System.out.println("value=" + field.get(obj)); } 

L’esecuzione di questo ha un output di:

value = [C @ 1b67f74
value = 3

 public abstract class Refl { /** Use: Refl.get(myObject,"xy[0].z"); */ public static T get(Object obj, String fieldPath) { return (T) getValue(obj, fieldPath); } public static Object getValue(Object obj, String fieldPath) { String[] fieldNames = fieldPath.split("[\\.\\[\\]]"); String success = ""; Object res = obj; for (String fieldName : fieldNames) { if (fieldName.isEmpty()) continue; int index = toIndex(fieldName); if (index >= 0) { try { res = ((Object[])res)[index]; } catch (ClassCastException cce) { throw new RuntimeException("cannot cast "+res.getClass()+" object "+res+" to array, path:"+success, cce); } catch (IndexOutOfBoundsException iobe) { throw new RuntimeException("bad index "+index+", array size "+((Object[])res).length +" object "+res +", path:"+success, iobe); } } else { Field field = getField(res.getClass(), fieldName); field.setAccessible(true); try { res = field.get(res); } catch (Exception ee) { throw new RuntimeException("cannot get value of ["+fieldName+"] from "+res.getClass()+" object "+res +", path:"+success, ee); } } success += fieldName + "."; } return res; } 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 in class " + clazz); } private static int toIndex(String s) { int res = -1; if (s != null && s.length() > 0 && Character.isDigit(s.charAt(0))) { try { res = Integer.parseInt(s); if (res < 0) { res = -1; } } catch (Throwable t) { res = -1; } } return res; } } 

Supporta il recupero dei campi e degli elementi dell'array, ad esempio:

 System.out.println(""+Refl.getValue(b,"xq[0].zy")); 

non vi è alcuna differenza tra punti e parentesi graffe, sono solo delimitatori e i nomi dei campi vuoti vengono ignorati:

 System.out.println(""+Refl.getValue(b,"xq[0].zy[value]")); System.out.println(""+Refl.getValue(b,"xq1.yzvalue")); System.out.println(""+Refl.getValue(b,"x[q.1]y]z[value")); 

C’è un altro modo, ho avuto la stessa situazione nel mio progetto. Ho risolto in questo modo

List list = HQL.list();

Nel suddetto linguaggio di interrogazione in ibernazione so in quale posto quali sono i miei oggetti, quindi quello che ho fatto è:

 for(Object[] obj : list){ String val = String.valueOf(obj[1]); int code =Integer.parseint(String.valueof(obj[0])); } 

in questo modo è ansible ottenere gli oggetti misti con facilità, ma è necessario sapere in anticipo in quale posto si ottiene il valore o è sufficiente verificare tramite la stampa dei valori da conoscere. scusa per il pessimo inglese, spero che questo aiuto