Javareflection:如何从对象获取字段值,而不知道它的类

说,我有一个返回带有一些对象的自定义List的方法。 它们作为Object返回给我。 我需要从这些对象中获取某个字段的值,但我不知道对象的类。

有没有办法通过Reflecion或其他方式做到这一点?

假设一个简单的案例,你的领域是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); } 

但这非常难看,我遗漏了所有的尝试捕获,并做了一些假设(公共领域,reflection可用,很好的安全管理器)。

如果你可以改变你的方法来返回List ,这变得非常容易,因为迭代器可以给你类型信息:

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

或者,如果您正在使用Java 1.4接口,其中generics不可用,但您知道应该在列表中的对象的类型…

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

不需要反思:)

如果您知道该字段所在的类,则可以使用reflection访问它。 这个例子(它在Groovy中,但方法调用是相同的)获取类Foo的Field对象并获取对象b值。 它表明你不必关心对象的确切具体类,重要的是你知道字段所在的类,并且该类是对象的具体类或超类。

 groovy:000> class Foo { def stuff = "asdf"} ===> true groovy:000> class Bar extends Foo {} ===> true groovy:000> b = new Bar() ===> Bar@1f2be27 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 

我强烈建议使用Javagenerics来指定该List中的对象类型,即。 List 。 如果你有汽车和卡车,你可以使用像List这样的通用超类/接口。

但是,您可以使用Spring的ReflectionUtils来使字段可访问,即使它们是私有的,如下面的runnable示例:

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

通过这种方式,您可以轻松获得混合对象,但您应该事先知道您获得的值是什么,或者您可以通过打印要知道的值来检查。 对不起英语不好,希望对你有所帮助