Отражение Java: как получить значение поля от объекта, не зная его classа

Скажем, у меня есть метод, который возвращает пользовательский List с некоторыми объектами. Они возвращаются как Object для меня. Мне нужно получить значение определенного поля из этих объектов, но я не знаю class объектов.

Есть ли способ сделать это через Reflecion или как-нибудь еще?

Предполагая простой случай, когда ваше поле открыто:

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

Но это довольно уродливо, и я упустил все попытки уловов и сделал ряд предположений (публичное поле, reflection доступно, хороший менеджер безопасности).

Если вы можете изменить свой метод, чтобы вернуть List , это становится очень простым, потому что iterator может предоставить вам информацию о типе:

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

Или, если вы используете интерфейс Java 1.4, где дженерики недоступны, но вы знаете тип объектов, которые должны быть в списке …

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

Не требуется никакого размышления 🙂

Если вы знаете, в каком classе находится поле, вы можете получить к нему доступ с помощью отражения. Этот пример (это в Groovy, но вызовы метода идентичны) получает объект Field для classа Foo и получает его значение для объекта b . Это показывает, что вам не нужно заботиться о конкретном конкретном classе объекта, важно то, что вы знаете class, в котором находится поле, и что этот class является либо конкретным classом, либо суперclassом объекта.

 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 

Я настоятельно рекомендую использовать Java-генераторы, чтобы указать, какой тип объекта находится в этом списке, т.е. List . Если у вас есть автомобили и грузовики, вы можете использовать обычный суперclass / интерфейс, как этот List .

Тем не менее, вы можете использовать Spring ReflectUtils, чтобы сделать поля доступными, даже если они являются частными, как приведенный ниже пример:

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

Запуск этого имеет выход:

значение = [C @ 1b67f74
Значение = 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; } } 

Он поддерживает выборку полей и элементов массива, например:

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

нет разницы между точками и фигурными скобками, они просто разделители, а пустые имена полей игнорируются:

 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")); 

Есть еще один способ, у меня такая же ситуация в моем проекте. я решил так

List list = HQL.list();

В вышеперечисленном языке запросов на hibernate я знаю, в каком месте находятся мои объекты, так что я сделал это:

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

таким образом вы можете легко получить смешанные объекты, но вы должны заранее знать, в каком месте вы получаете то или иное значение, или можете просто проверить, распечатывая значения, которые нужно знать. извините за плохой английский Я надеюсь, что эта помощь

  • Как получить строковое имя метода в java?
  • Как получить поля в объекте через reflection?
  • Значение генерирующего поля отражения
  • Java Reflection: как я могу получить все методы getter classа java и вызывать их
  • Отражение Java - влияние setAccessible (true)
  • Скопируйте все значения из полей одного classа в другой посредством отражения
  • Измените параметр строки annotations определения classа во время выполнения
  • Давайте будем гением компьютера.