说,我有一个方法可以返回带有一些对象的自定义List
。它们以Object
的形式返回给我。我需要从这些对象中获取某个字段的值,但我不知道对象的类。
有没有办法通过Reflecion或其他方式做到这一点?
答案 0 :(得分:43)
假设一个简单的案例,您的字段为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);
}
但这非常难看,我遗漏了所有的尝试捕获,并做出了许多假设(公共领域,反射可用,不错的安全经理)。
如果您可以更改方法以返回List<Foo>
,那么这变得非常简单,因为迭代器可以为您提供类型信息:
List<Foo> 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;
}
}
不需要反思:)
答案 1 :(得分:4)
如果您知道该字段所在的类,则可以使用反射访问该字段。这个例子(它在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
答案 2 :(得分:1)
我强烈建议使用Java泛型来指定该List中的对象类型,即。 List<Car>
。如果你有汽车和卡车,你可以使用像List<Vehicle>
这样的通用超类/接口。
但是,您可以使用Spring的ReflectionUtils来使字段可访问,即使它们是私有的,如下面的runnable示例所示:
List<Object> list = new ArrayList<Object>();
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
答案 3 :(得分:1)
public abstract class Refl {
/** Use: Refl.<TargetClass>get(myObject,"x.y[0].z"); */
public static<T> 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,"x.q[0].z.y"));
点和大括号之间没有区别,它们只是分隔符,空字段名称被忽略:
System.out.println(""+Refl.getValue(b,"x.q[0].z.y[value]"));
System.out.println(""+Refl.getValue(b,"x.q.1.y.z.value"));
System.out.println(""+Refl.getValue(b,"x[q.1]y]z[value"));
答案 4 :(得分:-1)
还有一种方法,我在项目中遇到了同样的情况。 我这样解决了
List<Object[]> list = HQL.list();
在上面的hibernate查询语言中,我知道在哪个地方我的对象是什么,所以我做的是:
for(Object[] obj : list){
String val = String.valueOf(obj[1]);
int code =Integer.parseint(String.valueof(obj[0]));
}
通过这种方式,您可以轻松获得混合对象,但您应该事先知道您获得的值是什么,或者您可以通过打印要知道的值进行检查。
抱歉英语不好
我希望这有帮助