问题:我想能够在
Java中一般访问
Java ojbect中的任何属性/字段,与动态语言(认为Groovy,JavaScript)一样.当时我正在写这个管道代码,我不知道它是什么类型的对象,或者是什么属性/字段名称.但是当我去使用它时,我会知道这个属性/字段名称.
我目前的解决方案:到目前为止,我已经编写了一个简单的包装类,它使用java.beans.Introspector来获取Bean / POJO的属性,并将它们作为Map< String,Object> ;.这是粗糙的,但适用于简单的案例. 我的问题是除了反映/转换为地图之外,还有什么其他方法来处理这个问题? 在我进一步走下去之前,我想知道是否有人知道如何从Rhino或者javax.script *中分解某些东西.*这个概念有一个深思熟虑的实现.或者也许是一个完全不同的做法,我没有考虑过. 编辑:是的,我熟悉反思(我相信Introspector在引擎盖下使用的是什么).如果有任何其他深思熟虑的解决方案,我只是好奇 编辑2:看起来最受欢迎的答案包括1)直接或通过辅助类反射,和/或2)映射到实现所需类成员的接口.我很感兴趣的是关于利用Groovy的评论.由于Groovy具有真正的鸭型,它是一种JVM语言,是否有一种方法可以在Groovy中创建一个简单的助手,并从Java中调用它?这真的很酷,可能更灵活,表现更好. 答:我把迈克的答案标记为最好,因为它是一个最接近的完整概念.对于这种情况我可能不会去那条路线,但这当然是一个有用的方法.任何看这个的人都应该确定阅读这里的对话,因为在那里还有很多有用的信息. 谢谢!
解决方法
如果您知道要公开的API集,比方说您需要访问长度方法和迭代器方法,则可以定义一个接口:
public interface TheInterfaceIWant { int length(); void quack(); }
并且您希望能够使用此接口访问不实现此接口的实例上的相应方法,则可以使用Proxy类:http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Proxy.html
所以你创建一个代理
final Object aDuck = ...; TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance( TheInterfaceIWant.class.getClassLoader(),new Class[] { TheInterfaceIWant.class },new InvocationHandler() { public Object invoke( Object proxy,Method method,Object[] args) throws Throwable { return aDuck.getClass().getMethod( method.getName(),method.getParameterTypes()).invoke(aDuck,args); } });
那么你可以使用包装器,就像使用动态类型语言的鸭子一样.
if (aDuckWrapper.length() > 0) { aDuckWrapper.quack(); }
这是一个全长的可运行示例,使用包装器打印“Quack”四次:
import java.lang.reflect.*; public class Duck { // The interface we use to access the duck typed object. public interface TheInterfaceIWant { int length(); void quack(); } // The underlying instance that does not implement TheInterfaceIWant! static final class Foo { public int length() { return 4; } public void quack() { System.out.println("Quack"); } } public static void main(String[] args) throws Exception { // Create an instance but cast away all useful type info. final Object aDuck = new Foo(); TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance( TheInterfaceIWant.class.getClassLoader(),new InvocationHandler() { public Object invoke( Object proxy,Object[] args) throws Throwable { return aDuck.getClass().getMethod( method.getName(),args); } }); for (int n = aDuckWrapper.length(); --n >= 0;) { // Calling aDuck.quack() here would be invalid since its an Object. aDuckWrapper.quack(); } } }