请考虑以下代码:
Class Demo
{
Person person = new Person("foo"); // assume Person class has a 'name' field.
//Now, how do I get the value of a field, using some expression.
String expression = "person.name";
}
现在,我想评估'表达式'以获取'name'属性的值。任何人都可以告诉我们该怎么做?
- 更新:'表达式'字符串我将从XML文件中获取它。那么,是否可以在该场景中使用“反射”? 'expression'字符串也可以进入更深层次,比如'person.birthday.date'。
答案 0 :(得分:3)
Java中没有本地方法可以做到这一点。存在各种其他选择。
一种方法是使用JXPath。这使用XPath样式的语法来查询对象。对你的目的来说,这可能有点矫枉过正,但无疑是有力的。
e.g。来自JXPath主页:
Address address = (Address)JXPathContext.newContext(vendor).
getValue("locations[address/zipCode='90210']/address");
在给定邮政编码为90210的情况下询问给定供应商对象的地址。因此,您可以导航对象层次结构并提供谓词以执行“SELECT .. WHERE”类型查询。
有关更多示例,请参阅this java.net文章(我写的东西的无耻插件)。
答案 1 :(得分:2)
通常在Java中,您可以创建getter来检索此信息。但是,如果您需要按名称获取字段的值,则应使用reflection。
然而,你的问题有些让我觉得你的问题更多地与设计而不是反思有关。你能告诉我们更多吗?
答案 2 :(得分:1)
你可以通过编写一个反射式解析器来自己做这类事情,但你也可以使用Spring的Expresion Evaluation语言,这几乎就是你想要的(Documentation!)。
你可以用它做一些很酷的事情;它是一种强大的语言,类似于JSP的EL脚本(也是一种选择)。你只需要传递一个“人”意味着什么的语境。
实施例<!/ P>
public class DoStuff {
class MyVariables {
private person;
public void getPerson() { return person; }
public void setPerson(Person person) { this.person = person;
}
public static Object eval( String input ) {
MyVariables myVariables = new MyVariables();
StandardEvaluationContext simpleContext = new StandardEvaluationContext(myVariables);
ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression( input );
return exp.getValue(context);
}
public static void main(String[] args) {
String name = (String)eval("person.name");//woot!
}
}
答案 3 :(得分:1)
您可以使用反射,但我建议使用工具来解析其他人建议的表达式。
但是,如果您的表达式简单,您可以执行以下操作:
public static Object GetFieldValue(Object obj, String expr) throws SecurityException, NoSuchFieldException, IllegalAccessException {
if (obj == null)
throw new IllegalArgumentException("obj");
if (expr == null || expr.isEmpty())
throw new IllegalArgumentException("expr");
String[] parts = expr.split("\\.");
if (parts.length > 0) {
Object currentFieldValue = obj;
for (String fieldName : parts) {
Field field = currentFieldValue.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
currentFieldValue = field.get(currentFieldValue);
}
return currentFieldValue;
}
return null;
}
答案 4 :(得分:0)
假设您不想使用String expression = person.name;
的简单路线(person.name
附近没有引号),则需要reflection。
解析任意表达并不容易;如果你想用参数调用方法,那么你正在寻找一种自定义脚本语言。但只是为了访问一个成员,这并不难。但是在我给你编写任何代码之前,我想知道为什么你想要普通Java在这里做任意表达式。
编辑:此代码可以解决问题:
public static Object getValue(Object obj, String path)
throws NoSuchFieldException,
IllegalArgumentException,
IllegalAccessException {
Object currentObj = obj;
while (true) {
int indexOfDot = path.indexOf('.');
boolean lastIter = indexOfDot < 0;
String fieldName = lastIter ? path : path.substring(0, indexOfDot);
Field f = currentObj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
currentObj = f.get(currentObj);
if (lastIter)
return currentObj;
path = path.substring(indexOfDot + 1);
}
}
答案 5 :(得分:0)
'正确'的方法是在Person中使用一个名为getName()的getter方法,它返回name的值。
答案 6 :(得分:0)
虽然你可以用反射来做到这一点(java.bean
可能更有意义),但反射的使用往往表明存在混淆。
为什么要解释一些文字?你是故意写一个翻译吗?是否真的应该将person
的引用视为对象?告诉我们你的意图。
答案 7 :(得分:0)
如果您希望允许用户通过提供表达式(例如您的person.name表达式)来自定义您的程序,您可以查看在程序中嵌入groovy或jython并在该上下文中运行它们的表达式。这是嵌入groovy的第一个谷歌热门。 http://groovy.codehaus.org/Embedding+Groovy
答案 8 :(得分:0)
如果数据是XML DOM,则XPath可能是最佳选择。如果您想为Unified Expression Language添加自己的支持,可以按implementing a few classes添加。如果您想通过javax.script使用几乎任何脚本语言(需要Java 6),请查看this library of scripting engines。
开箱即用,您可以使用Java 6执行此操作:
public class ResolveMe {
public URI uri;
public static void main(String[] args)
throws ScriptException, URISyntaxException {
ResolveMe myObject = new ResolveMe();
myObject.uri = new URI("http://stackoverflow.com/foo");
String expression = "myObject.uri.host";
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem
.getEngineByMimeType("application/javascript");
engine.put("myObject", myObject);
System.out.println(engine.eval(expression));
}
}
答案 9 :(得分:0)
你真的需要“Name”成为java对象的成员吗?你可以将它存储在哈希表中并使用查找吗?
(提示:如果你在对象内部对它进行操作,你只需要它成为一个对象的成员,即使这样你有一个对象存储它的'数据在内部作为哈希,如果你想的话)
答案 10 :(得分:0)
不要自己做这么辛苦的工作。使用执行此操作的库。 Apache common的bean utils有一个方法BeanUtils.getProperty(Object bean,String name),你可以将bean和属性传递给它。例如,BeanUtils.getProperty(foo,“name”)将为您提供foo的Person的name属性(您不会使用“person.name”,因为这将等同于foo.getPerson()。getName() )。
您可以从maven中央存储库下载BeanUtils jar: http://repo1.maven.org/maven2/commons-beanutils/commons-beanutils/1.8.0/commons-beanutils-1.8.0.jar
可能需要http://repo1.maven.org/maven2/commons-beanutils层次结构中的某些依赖项,我不确定。你可以google for apache commons BeanUtils jar,看看你是否可以通过这种方式获得依赖项,但是你可以单独使用jar。