我如何在Clojure中实现Java接口?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (14)

我如何创建一个实现此接口并从Java代码调用的Clojure对象?

public interface Doer {
   public String doSomethin(String input);
}

Doer clojureDoer = ?;

String output = clojureDoer.doSomethin(input);
提问于
用户回答回答于

reify非常适合实现接口 - proxy重载,老旧和缓慢,所以应尽可能避免。一个实现看起来像:

(reify Doer
  (doSomethin [this input]
    (...whatever...)))

请注意,关于使用的现有答案proxy具有不正确的语法,如果您决定继续使用代理:代理采用隐式this参数,而不是命名的第一个参数。

用户回答回答于

Clojure 1.6开始,首选方法如下。假设你在你的类路径上有Clojure 1.6 jar和下面的clojure文件(或者它的编译等价物):

(ns my.clojure.namespace
  (:import [my.java.package Doer]))

(defn reify-doer
  "Some docstring about what this specific implementation of Doer
  does differently than the other ones. For example, this one does
  not actually do anything but print the given string to stdout."
  []
  (reify
    Doer
    (doSomethin [this in] (println in))))

那么,从Java,你可以如下访问它:

package my.other.java.package.or.maybe.the.same.one;

import my.java.package.Doer;
import clojure.lang.IFn;
import clojure.java.api.Clojure;

public class ClojureDoerUser {
    // First, we need to instruct the JVM to compile/load our
    // Clojure namespace. This should, obviously, only be done once.
    static {
        IFn require = Clojure.var("clojure.core", "require");
        require.invoke(Clojure.read("my.clojure.namespace"));
        // Clojure.var() does a somewhat expensive lookup; if we had more than
        // one Clojure namespace to load, so as a general rule its result should
        // always be saved into a variable.
        // The call to Clojure.read is necessary because require expects a Clojure
        // Symbol, for which there is no more direct official Clojure API.
    }

    // We can now lookup the function we want from our Clojure namespace.
    private static IFn doerFactory = Clojure.var("my.clojure.namespace", "reify-doer");

    // Optionally, we can wrap the doerFactory IFn into a Java wrapper,
    // to isolate the rest of the code from our Clojure dependency.
    // And from the need to typecast, as IFn.invoke() returns Object.
    public static Doer createDoer() {
        return (Doer) doerFactory.invoke();
    }
    public static void main(String[] args) {
        Doer doer = (Doer) doerFactory.invoke();
        doer.doSomethin("hello, world");
    }
}

扫码关注云+社区