在Java中模拟鸭子打字

前端之家收集整理的这篇文章主要介绍了在Java中模拟鸭子打字前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
问题:我想能够在 Java中一般访问 Java ojbect中的任何属性/字段,与动态语言(认为Groovy,JavaScript)一样.当时我正在写这个管道代码,我不知道它是什么类型的对象,或者是什么属性/字段名称.但是当我去使用它时,我会知道这个属性/字段名称.

我目前的解决方案:到目前为止,我已经编写了一个简单的包装类,它使用java.beans.Introspector来获取Bean / POJO的属性,并将它们作为Map< String,Object&gt ;.这是粗糙的,但适用于简单的案例. 我的问题是除了反映/转换为地图之外,还有什么其他方法来处理这个问题? 在我进一步走下去之前,我想知道是否有人知道如何从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();
    }
  }
}

猜你在找的Java相关文章