当前位置: 首页 > 面试题库 >

模拟Java中的鸭子输入

夏侯星洲
2023-03-14
问题内容

问题: 我希望能够 在Java中 以通用方式访问 Java对象
任何属性/字段,就像动态语言(例如Groovy,JavaScript)一样。在编写此管道代码时,我不知道它是什么类型的对象或属性/字段名称是什么。但是当我使用它时,我将知道属性/字段名称。

我当前的解决方案: 到目前为止,我已经编写了一个简单的包装器类,该包装器类java.beans.Introspector用于获取Bean /
POJO的属性并将其公开为Map<String, Object>。它很粗糙,但适用于简单的情况。

我的问题 是,除了反射/转换为地图外,还有什么其他方法可用来解决此问题?

在我进一步走这条路之前,我想知道是否有人知道我如何可以从Rhino中吞噬某些东西,或者也许javax.script.*有一个经过深思熟虑地实现了这一概念的人。也许我没有考虑过一种完全不同的方法。

编辑: 是的,我对反射很熟悉(我相信这是Introspector在后台使用的功能)。我只是好奇是否还有其他经过深思熟虑的解决方案。

编辑2:
看来,最流行的答案包括1)直接或通过助手类进行反射,和/或2)映射到实现所需类成员的接口。谈到利用Groovy的评论我真的很感兴趣。由于Groovy具有真正的鸭子类型并且是JVM语言,是否有一种方法可以在Groovy中创建简单的帮助程序并从Java调用它?这真的很酷,可能更灵活并且性能更好。

答:
我将迈克的答案标记为最佳,因为这是一个最接近的完整概念。对于这种特殊情况,我可能不会走这条路,但这无疑是一种有用的方法。查看此内容的任何人都应该确保阅读此处的对话,因为那里也有很多有用的信息。

谢谢!


问题答案:

如果知道要公开的一组API,例如说您想访问length方法和迭代器方法,则可以定义一个接口:

public interface TheInterfaceIWant {
  int length();
  void quack();
}
如果您希望能够使用此接口来访问未实现此接口的实例上的相应方法,则可以使用代理类: 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 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);
          }
        });

    for (int n = aDuckWrapper.length(); --n >= 0;) {
      // Calling aDuck.quack() here would be invalid since its an Object.
      aDuckWrapper.quack();
    }
  }
}


 类似资料:
  • 问题内容: 我最近听说过鸭式打字,并且阅读了有关它的Wikipedia文章,但是我很难将示例转换为Java,这确实有助于我的理解。 谁能给出Java中鸭子类型的清晰示例,以及我将如何使用它? 问题答案: Java设计上不适合鸭子输入。您可能选择这样做的方式是反思: 但是我主张使用一种动态语言(例如Groovy)来实现,在这种语言中,它更有意义: 参考

  • “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” 我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。 比如在python中,有很多file-like的东西,比如StringIO,GzipFile,socket。它们有很多相同的方法,我们把它们当作文件使用。 又比如list.extend()方法中,我们并不关心它的参数是不是list,只要它是可迭代的,

  • 该程序应模拟滚动两个骰子,并计算和。添加一个循环,使程序可以玩10,000个游戏。添加计数器,计算玩家赢了多少次,输了多少次。在10,000场比赛结束时,计算获胜的概率[即赢/(赢+输)]并输出该值。从长远来看,谁会赢得最多的比赛,你还是房子?注意:要生成一个随机数x,其中0x≤<1,使用x=math.random();例如,乘以6并转换为一个整数,结果是一个介于0和5之间的整数。

  • 问题内容: 我正在尝试为需要用户输入的方法创建一些JUnit测试。被测方法看起来类似于以下方法: 有没有一种方法可以自动将程序传递给int而不是我或其他人在JUnit测试方法中手动执行此操作?像模拟用户输入一样? 提前致谢。 问题答案: 你可以通过调用来用自己的流替换可以是一个字节数组: 通过将IN和OUT作为参数传递,不同的方法可以使此方法更具可测试性:

  • 问题内容: 我正在尝试测试从中获取输入的函数,而我目前正在使用类似以下内容进行测试: 以测试自动化的名义,有什么方法可以伪造输入? 问题答案: 简短的答案是猴子补丁 。 这是一个使用a的简单示例,该示例丢弃提示并返回我们想要的内容。 被测系统 测试用例:

  • 本文向大家介绍详细介绍Python的鸭子类型,包括了详细介绍Python的鸭子类型的使用技巧和注意事项,需要的朋友参考一下 鸭子类型基本定义 首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。 以下是维基百科中对鸭子类型得论述: 在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实